提交 df8dc74e 编写于 作者: L Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-2.6

This can be broken down into these major areas:
 - Documentation updates (language translations and fixes, as
   well as kobject and kset documenatation updates.)
 - major kset/kobject/ktype rework and fixes.  This cleans up the
   kset and kobject and ktype relationship and architecture,
   making sense of things now, and good documenation and samples
   are provided for others to use.  Also the attributes for
   kobjects are much easier to handle now.  This cleaned up a LOT
   of code all through the kernel, making kobjects easier to use
   if you want to.
 - struct bus_type has been reworked to now handle the lifetime
   rules properly, as the kobject is properly dynamic.
 - struct driver has also been reworked, and now the lifetime
   issues are resolved.
 - the block subsystem has been converted to use struct device
   now, and not "raw" kobjects.  This patch has been in the -mm
   tree for over a year now, and finally all the issues are
   worked out with it.  Older distros now properly work with new
   kernels, and no userspace updates are needed at all.
 - nozomi driver is added.  This has also been in -mm for a long
   time, and many people have asked for it to go in.  It is now
   in good enough shape to do so.
 - lots of class_device conversions to use struct device instead.
   The tree is almost all cleaned up now, only SCSI and IB is the
   remaining code to fix up...

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-2.6: (196 commits)
  Driver core: coding style fixes
  Kobject: fix coding style issues in kobject c files
  Kobject: fix coding style issues in kobject.h
  Driver core: fix coding style issues in device.h
  spi: use class iteration api
  scsi: use class iteration api
  rtc: use class iteration api
  power supply : use class iteration api
  ieee1394: use class iteration api
  Driver Core: add class iteration api
  Driver core: Cleanup get_device_parent() in device_add() and device_move()
  UIO: constify function pointer tables
  Driver Core: constify the name passed to platform_device_register_simple
  driver core: fix build with SYSFS=n
  sysfs: make SYSFS_DEPRECATED depend on SYSFS
  Driver core: use LIST_HEAD instead of call to INIT_LIST_HEAD in __init
  kobject: add sample code for how to use ksets/ktypes/kobjects
  kobject: add sample code for how to use kobjects in a simple manner.
  kobject: update the kobject/kset documentation
  kobject: remove old, outdated documentation.
  ...
此差异已折叠。
...@@ -17,9 +17,9 @@ The User Interface ...@@ -17,9 +17,9 @@ The User Interface
------------------ ------------------
The Linux Plug and Play user interface provides a means to activate PnP devices The Linux Plug and Play user interface provides a means to activate PnP devices
for legacy and user level drivers that do not support Linux Plug and Play. The for legacy and user level drivers that do not support Linux Plug and Play. The
user interface is integrated into driverfs. user interface is integrated into sysfs.
In addition to the standard driverfs file the following are created in each In addition to the standard sysfs file the following are created in each
device's directory: device's directory:
id - displays a list of support EISA IDs id - displays a list of support EISA IDs
options - displays possible resource configurations options - displays possible resource configurations
......
...@@ -133,7 +133,7 @@ During its startup the Linux/390 system checks for peripheral devices. Each ...@@ -133,7 +133,7 @@ During its startup the Linux/390 system checks for peripheral devices. Each
of those devices is uniquely defined by a so called subchannel by the ESA/390 of those devices is uniquely defined by a so called subchannel by the ESA/390
channel subsystem. While the subchannel numbers are system generated, each channel subsystem. While the subchannel numbers are system generated, each
subchannel also takes a user defined attribute, the so called device number. subchannel also takes a user defined attribute, the so called device number.
Both subchannel number and device number cannot exceed 65535. During driverfs Both subchannel number and device number cannot exceed 65535. During sysfs
initialisation, the information about control unit type and device types that initialisation, the information about control unit type and device types that
imply specific I/O commands (channel command words - CCWs) in order to operate imply specific I/O commands (channel command words - CCWs) in order to operate
the device are gathered. Device drivers can retrieve this set of hardware the device are gathered. Device drivers can retrieve this set of hardware
......
...@@ -1021,7 +1021,7 @@ void read_slab_dir(void) ...@@ -1021,7 +1021,7 @@ void read_slab_dir(void)
char *t; char *t;
int count; int count;
if (chdir("/sys/slab")) if (chdir("/sys/kernel/slab"))
fatal("SYSFS support for SLUB not active\n"); fatal("SYSFS support for SLUB not active\n");
dir = opendir("."); dir = opendir(".");
......
...@@ -63,7 +63,7 @@ In case you forgot to enable debugging on the kernel command line: It is ...@@ -63,7 +63,7 @@ In case you forgot to enable debugging on the kernel command line: It is
possible to enable debugging manually when the kernel is up. Look at the possible to enable debugging manually when the kernel is up. Look at the
contents of: contents of:
/sys/slab/<slab name>/ /sys/kernel/slab/<slab name>/
Look at the writable files. Writing 1 to them will enable the Look at the writable files. Writing 1 to them will enable the
corresponding debug option. All options can be set on a slab that does corresponding debug option. All options can be set on a slab that does
......
此差异已折叠。
Chinese translated version of Documentation/HOWTO Chinese translated version of Documentation/HOWTO
If you have any comment or update to the content, please contact the If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have problem original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer, if this translation is outdated help. Contact the Chinese maintainer if this translation is outdated
or there is problem with translation. or if there is a problem with the translation.
Maintainer: Greg Kroah-Hartman <greg@kroah.com> Maintainer: Greg Kroah-Hartman <greg@kroah.com>
Chinese maintainer: Li Yang <leoli@freescale.com> Chinese maintainer: Li Yang <leoli@freescale.com>
...@@ -85,7 +85,7 @@ Linux内核源代码都是在GPL(通用公共许可证)的保护下发布的 ...@@ -85,7 +85,7 @@ Linux内核源代码都是在GPL(通用公共许可证)的保护下发布的
Linux内核代码中包含有大量的文档。这些文档对于学习如何与内核社区互动有着 Linux内核代码中包含有大量的文档。这些文档对于学习如何与内核社区互动有着
不可估量的价值。当一个新的功能被加入内核,最好把解释如何使用这个功能的文 不可估量的价值。当一个新的功能被加入内核,最好把解释如何使用这个功能的文
档也放进内核。当内核的改动导致面向用户空间的接口发生变化时,最好将相关信 档也放进内核。当内核的改动导致面向用户空间的接口发生变化时,最好将相关信
息或手册页(manpages)的补丁发到mtk-manpages@gmx.net,以向手册页(manpages) 息或手册页(manpages)的补丁发到mtk.manpages@gmail.com,以向手册页(manpages)
的维护者解释这些变化。 的维护者解释这些变化。
以下是内核代码中需要阅读的文档: 以下是内核代码中需要阅读的文档:
...@@ -218,6 +218,8 @@ kernel.org网站的pub/linux/kernel/v2.6/目录下找到它。它的开发遵循 ...@@ -218,6 +218,8 @@ kernel.org网站的pub/linux/kernel/v2.6/目录下找到它。它的开发遵循
时,一个新的-rc版本就会被发布。计划是每周都发布新的-rc版本。 时,一个新的-rc版本就会被发布。计划是每周都发布新的-rc版本。
- 这个过程一直持续下去直到内核被认为达到足够稳定的状态,持续时间大概是 - 这个过程一直持续下去直到内核被认为达到足够稳定的状态,持续时间大概是
6个星期。 6个星期。
- 以下地址跟踪了在每个-rc发布中发现的退步列表:
http://kernelnewbies.org/known_regressions
关于内核发布,值得一提的是Andrew Morton在linux-kernel邮件列表中如是说: 关于内核发布,值得一提的是Andrew Morton在linux-kernel邮件列表中如是说:
“没有人知道新内核何时会被发布,因为发布是根据已知bug的情况来决定 “没有人知道新内核何时会被发布,因为发布是根据已知bug的情况来决定
......
Chinese translated version of Documentation/SubmittingDrivers
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: Li Yang <leo@zh-kernel.org>
---------------------------------------------------------------------
Documentation/SubmittingDrivers 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 李阳 Li Yang <leo@zh-kernel.org>
中文版翻译者: 李阳 Li Yang <leo@zh-kernel.org>
中文版校译者: 陈琦 Maggie Chen <chenqi@beyondsoft.com>
王聪 Wang Cong <xiyou.wangcong@gmail.com>
张巍 Zhang Wei <Wei.Zhang@freescale.com>
以下为正文
---------------------------------------------------------------------
如何向 Linux 内核提交驱动程序
-----------------------------
这篇文档将会解释如何向不同的内核源码树提交设备驱动程序。请注意,如果你感
兴趣的是显卡驱动程序,你也许应该访问 XFree86 项目(http://www.xfree86.org/)
和/或 X.org 项目 (http://x.org)。
另请参阅 Documentation/SubmittingPatches 文档。
分配设备号
----------
块设备和字符设备的主设备号与从设备号是由 Linux 命名编号分配权威 LANANA(
现在是 Torben Mathiasen)负责分配。申请的网址是 http://www.lanana.org/。
即使不准备提交到主流内核的设备驱动也需要在这里分配设备号。有关详细信息,
请参阅 Documentation/devices.txt。
如果你使用的不是已经分配的设备号,那么当你提交设备驱动的时候,它将会被强
制分配一个新的设备号,即便这个设备号和你之前发给客户的截然不同。
设备驱动的提交对象
------------------
Linux 2.0:
此内核源码树不接受新的驱动程序。
Linux 2.2:
此内核源码树不接受新的驱动程序。
Linux 2.4:
如果所属的代码领域在内核的 MAINTAINERS 文件中列有一个总维护者,
那么请将驱动程序提交给他。如果此维护者没有回应或者你找不到恰当的
维护者,那么请联系 Willy Tarreau <w@1wt.eu>。
Linux 2.6:
除了遵循和 2.4 版内核同样的规则外,你还需要在 linux-kernel 邮件
列表上跟踪最新的 API 变化。向 Linux 2.6 内核提交驱动的顶级联系人
是 Andrew Morton <akpm@osdl.org>。
决定设备驱动能否被接受的条件
----------------------------
许可: 代码必须使用 GNU 通用公开许可证 (GPL) 提交给 Linux,但是
我们并不要求 GPL 是唯一的许可。你或许会希望同时使用多种
许可证发布,如果希望驱动程序可以被其他开源社区(比如BSD)
使用。请参考 include/linux/module.h 文件中所列出的可被
接受共存的许可。
版权: 版权所有者必须同意使用 GPL 许可。最好提交者和版权所有者
是相同个人或实体。否则,必需列出授权使用 GPL 的版权所有
人或实体,以备验证之需。
接口: 如果你的驱动程序使用现成的接口并且和其他同类的驱动程序行
为相似,而不是去发明无谓的新接口,那么它将会更容易被接受。
如果你需要一个 Linux 和 NT 的通用驱动接口,那么请在用
户空间实现它。
代码: 请使用 Documentation/CodingStyle 中所描述的 Linux 代码风
格。如果你的某些代码段(例如那些与 Windows 驱动程序包共
享的代码段)需要使用其他格式,而你却只希望维护一份代码,
那么请将它们很好地区分出来,并且注明原因。
可移植性: 请注意,指针并不永远是 32 位的,不是所有的计算机都使用小
尾模式 (little endian) 存储数据,不是所有的人都拥有浮点
单元,不要随便在你的驱动程序里嵌入 x86 汇编指令。只能在
x86 上运行的驱动程序一般是不受欢迎的。虽然你可能只有 x86
硬件,很难测试驱动程序在其他平台上是否可用,但是确保代码
可以被轻松地移植却是很简单的。
清晰度: 做到所有人都能修补这个驱动程序将会很有好处,因为这样你将
会直接收到修复的补丁而不是 bug 报告。如果你提交一个试图
隐藏硬件工作机理的驱动程序,那么它将会被扔进废纸篓。
电源管理: 因为 Linux 正在被很多移动设备和桌面系统使用,所以你的驱
动程序也很有可能被使用在这些设备上。它应该支持最基本的电
源管理,即在需要的情况下实现系统级休眠和唤醒要用到的
.suspend 和 .resume 函数。你应该检查你的驱动程序是否能正
确地处理休眠与唤醒,如果实在无法确认,请至少把 .suspend
函数定义成返回 -ENOSYS(功能未实现)错误。你还应该尝试确
保你的驱动在什么都不干的情况下将耗电降到最低。要获得驱动
程序测试的指导,请参阅
Documentation/power/drivers-testing.txt。有关驱动程序电
源管理问题相对全面的概述,请参阅
Documentation/power/devices.txt。
管理: 如果一个驱动程序的作者还在进行有效的维护,那么通常除了那
些明显正确且不需要任何检查的补丁以外,其他所有的补丁都会
被转发给作者。如果你希望成为驱动程序的联系人和更新者,最
好在代码注释中写明并且在 MAINTAINERS 文件中加入这个驱动
程序的条目。
不影响设备驱动能否被接受的条件
------------------------------
供应商: 由硬件供应商来维护驱动程序通常是一件好事。不过,如果源码
树里已经有其他人提供了可稳定工作的驱动程序,那么请不要期
望“我是供应商”会成为内核改用你的驱动程序的理由。理想的情
况是:供应商与现有驱动程序的作者合作,构建一个统一完美的
驱动程序。
作者: 驱动程序是由大的 Linux 公司研发还是由你个人编写,并不影
响其是否能被内核接受。没有人对内核源码树享有特权。只要你
充分了解内核社区,你就会发现这一点。
资源列表
--------
Linux 内核主源码树:
ftp.??.kernel.org:/pub/linux/kernel/...
?? == 你的国家代码,例如 "cn"、"us"、"uk"、"fr" 等等
Linux 内核邮件列表:
linux-kernel@vger.kernel.org
[可通过向majordomo@vger.kernel.org发邮件来订阅]
Linux 设备驱动程序,第三版(探讨 2.6.10 版内核):
http://lwn.net/Kernel/LDD3/ (免费版)
LWN.net:
每周内核开发活动摘要 - http://lwn.net/
2.6 版中 API 的变更:
http://lwn.net/Articles/2.6-kernel-api/
将旧版内核的驱动程序移植到 2.6 版:
http://lwn.net/Articles/driver-porting/
KernelTrap:
Linux 内核的最新动态以及开发者访谈
http://kerneltrap.org/
内核新手(KernelNewbies):
为新的内核开发者提供文档和帮助
http://kernelnewbies.org/
Linux USB项目:
http://www.linux-usb.org/
写内核驱动的“不要”(Arjan van de Ven著):
http://www.fenrus.org/how-to-not-write-a-device-driver-paper.pdf
内核清洁工 (Kernel Janitor):
http://janitor.kernelnewbies.org/
Chinese translated version of Documentation/SubmittingPatches
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: TripleX Chung <triplex@zh-kernel.org>
---------------------------------------------------------------------
Documentation/SubmittingPatches 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 钟宇 TripleX Chung <triplex@zh-kernel.org>
中文版翻译者: 钟宇 TripleX Chung <triplex@zh-kernel.org>
中文版校译者: 李阳 Li Yang <leo@zh-kernel.org>
王聪 Wang Cong <xiyou.wangcong@gmail.com>
以下为正文
---------------------------------------------------------------------
如何让你的改动进入内核
或者
获得亲爱的 Linus Torvalds 的关注和处理
----------------------------------
对于想要将改动提交到 Linux 内核的个人或者公司来说,如果不熟悉“规矩”,
提交的流程会让人畏惧。本文档收集了一系列建议,这些建议可以大大的提高你
的改动被接受的机会。
阅读 Documentation/SubmitChecklist 来获得在提交代码前需要检查的项目的列
表。如果你在提交一个驱动程序,那么同时阅读一下
Documentation/SubmittingDrivers 。
--------------------------
第一节 - 创建并发送你的改动
--------------------------
1) "diff -up"
-----------
使用 "diff -up" 或者 "diff -uprN" 来创建补丁。
所有内核的改动,都是以补丁的形式呈现的,补丁由 diff(1) 生成。创建补丁的
时候,要确认它是以 "unified diff" 格式创建的,这种格式由 diff(1) 的 '-u'
参数生成。而且,请使用 '-p' 参数,那样会显示每个改动所在的C函数,使得
产生的补丁容易读得多。补丁应该基于内核源代码树的根目录,而不是里边的任
何子目录。
为一个单独的文件创建补丁,一般来说这样做就够了:
SRCTREE= linux-2.6
MYFILE= drivers/net/mydriver.c
cd $SRCTREE
cp $MYFILE $MYFILE.orig
vi $MYFILE # make your change
cd ..
diff -up $SRCTREE/$MYFILE{.orig,} > /tmp/patch
为多个文件创建补丁,你可以解开一个没有修改过的内核源代码树,然后和你自
己的代码树之间做 diff 。例如:
MYSRC= /devel/linux-2.6
tar xvfz linux-2.6.12.tar.gz
mv linux-2.6.12 linux-2.6.12-vanilla
diff -uprN -X linux-2.6.12-vanilla/Documentation/dontdiff \
linux-2.6.12-vanilla $MYSRC > /tmp/patch
"dontdiff" 是内核在编译的时候产生的文件的列表,列表中的文件在 diff(1)
产生的补丁里会被跳过。"dontdiff" 文件被包含在2.6.12和之后版本的内核源代
码树中。对于更早的内核版本,你可以从
<http://www.xenotime.net/linux/doc/dontdiff> 获取它。
确定你的补丁里没有包含任何不属于这次补丁提交的额外文件。记得在用diff(1)
生成补丁之后,审阅一次补丁,以确保准确。
如果你的改动很散乱,你应该研究一下如何将补丁分割成独立的部分,将改动分
割成一系列合乎逻辑的步骤。这样更容易让其他内核开发者审核,如果你想你的
补丁被接受,这是很重要的。下面这些脚本能够帮助你做这件事情:
Quilt:
http://savannah.nongnu.org/projects/quilt
Andrew Morton 的补丁脚本:
http://www.zip.com.au/~akpm/linux/patches/
作为这些脚本的替代,quilt 是值得推荐的补丁管理工具(看上面的链接)。
2)描述你的改动。
描述你的改动包含的技术细节。
要多具体就写多具体。最糟糕的描述可能是像下面这些语句:“更新了某驱动程
序”,“修正了某驱动程序的bug”,或者“这个补丁包含了某子系统的修改,请
使用。”
如果你的描述开始变长,这表示你也许需要拆分你的补丁了,请看第3小节,
继续。
3)拆分你的改动
将改动拆分,逻辑类似的放到同一个补丁文件里。
例如,如果你的改动里同时有bug修正和性能优化,那么把这些改动才分到两个或
者更多的补丁文件中。如果你的改动包含对API的修改,并且修改了驱动程序来适
应这些新的API,那么把这些修改分成两个补丁。
另一方面,如果你将一个单独的改动做成多个补丁文件,那么将它们合并成一个
单独的补丁文件。这样一个逻辑上单独的改动只被包含在一个补丁文件里。
如果有一个补丁依赖另外一个补丁来完成它的改动,那没问题。简单的在你的补
丁描述里指出“这个补丁依赖某补丁”就好了。
如果你不能将补丁浓缩成更少的文件,那么每次大约发送出15个,然后等待审查
和整合。
4)选择 e-mail 的收件人
看一遍 MAINTAINERS 文件和源代码,看看你所的改动所在的内核子系统有没有指
定的维护者。如果有,给他们发e-mail。
如果没有找到维护者,或者维护者没有反馈,将你的补丁发送到内核开发者主邮
件列表 linux-kernel@vger.kernel.org。大部分的内核开发者都跟踪这个邮件列
表,可以评价你的改动。
每次不要发送超过15个补丁到 vger 邮件列表!!!
Linus Torvalds 是决定改动能否进入 Linux 内核的最终裁决者。他的 e-mail
地址是 <torvalds@linux-foundation.org> 。他收到的 e-mail 很多,所以一般
的说,最好别给他发 e-mail。
那些修正bug,“显而易见”的修改或者是类似的只需要很少讨论的补丁可以直接
发送或者CC给Linus。那些需要讨论或者没有很清楚的好处的补丁,一般先发送到
linux-kernel邮件列表。只有当补丁被讨论得差不多了,才提交给Linus。
5)选择CC( e-mail 抄送)列表
除非你有理由不这样做,否则CC linux-kernel@vger.kernel.org。
除了 Linus 之外,其他内核开发者也需要注意到你的改动,这样他们才能评论你
的改动并提供代码审查和建议。linux-kernel 是 Linux 内核开发者主邮件列表
。其它的邮件列表为特定的子系统提供服务,比如 USB,framebuffer 设备,虚
拟文件系统,SCSI 子系统,等等。查看 MAINTAINERS 文件来获得和你的改动有
关的邮件列表。
Majordomo lists of VGER.KERNEL.ORG at:
<http://vger.kernel.org/vger-lists.html>
如果改动影响了用户空间和内核之间的接口,请给 MAN-PAGES 的维护者(列在
MAITAINERS 文件里的)发送一个手册页(man-pages)补丁,或者至少通知一下改
变,让一些信息有途径进入手册页。
即使在第四步的时候,维护者没有作出回应,也要确认在修改他们的代码的时候
,一直将维护者拷贝到CC列表中。
对于小的补丁,你也许会CC到 Adrian Bunk 管理的搜集琐碎补丁的邮件列表
(Trivial Patch Monkey)trivial@kernel.org,那里专门收集琐碎的补丁。下面这样
的补丁会被看作“琐碎的”补丁:
文档的拼写修正。
修正会影响到 grep(1) 的拼写。
警告信息修正(频繁的打印无用的警告是不好的。)
编译错误修正(代码逻辑的确是对的,只是编译有问题。)
运行时修正(只要真的修正了错误。)
移除使用了被废弃的函数/宏的代码(例如 check_region。)
联系方式和文档修正。
用可移植的代码替换不可移植的代码(即使在体系结构相关的代码中,既然有
人拷贝,只要它是琐碎的)
任何文件的作者/维护者对该文件的改动(例如 patch monkey 在重传模式下)
URL: <http://www.kernel.org/pub/linux/kernel/people/bunk/trivial/>
(译注,关于“琐碎补丁”的一些说明:因为原文的这一部分写得比较简单,所以不得不
违例写一下译注。"trivial"这个英文单词的本意是“琐碎的,不重要的。”但是在这里
有稍微有一些变化,例如对一些明显的NULL指针的修正,属于运行时修正,会被归类
到琐碎补丁里。虽然NULL指针的修正很重要,但是这样的修正往往很小而且很容易得到
检验,所以也被归入琐碎补丁。琐碎补丁更精确的归类应该是
“simple, localized & easy to verify”,也就是说简单的,局部的和易于检验的。
trivial@kernel.org邮件列表的目的是针对这样的补丁,为提交者提供一个中心,来
降低提交的门槛。)
6)没有 MIME 编码,没有链接,没有压缩,没有附件,只有纯文本。
Linus 和其他的内核开发者需要阅读和评论你提交的改动。对于内核开发者来说
,可以“引用”你的改动很重要,使用一般的 e-mail 工具,他们就可以在你的
代码的任何位置添加评论。
因为这个原因,所有的提交的补丁都是 e-mail 中“内嵌”的。
警告:如果你使用剪切-粘贴你的补丁,小心你的编辑器的自动换行功能破坏你的
补丁。
不要将补丁作为 MIME 编码的附件,不管是否压缩。很多流行的 e-mail 软件不
是任何时候都将 MIME 编码的附件当作纯文本发送的,这会使得别人无法在你的
代码中加评论。另外,MIME 编码的附件会让 Linus 多花一点时间来处理,这就
降低了你的改动被接受的可能性。
警告:一些邮件软件,比如 Mozilla 会将你的信息以如下格式发送:
---- 邮件头 ----
Content-Type: text/plain; charset=us-ascii; format=flowed
---- 邮件头 ----
问题在于 “format=flowed” 会让接收端的某些邮件软件将邮件中的制表符替换
成空格以及做一些类似的替换。这样,你发送的时候看起来没问题的补丁就被破
坏了。
要修正这个问题,只需要将你的 mozilla 的 defaults/pref/mailnews.js 文件
里的
pref("mailnews.send_plaintext_flowed", false); // RFC 2646=======
修改成
pref("mailnews.display.disable_format_flowed_support", true);
就可以了。
7) e-mail 的大小
给 Linus 发送补丁的时候,永远按照第6小节说的做。
大的改动对邮件列表不合适,对某些维护者也不合适。如果你的补丁,在不压缩
的情况下,超过了40kB,那么你最好将补丁放在一个能通过 internet 访问的服
务器上,然后用指向你的补丁的 URL 替代。
8) 指出你的内核版本
在标题和在补丁的描述中,指出补丁对应的内核的版本,是很重要的。
如果补丁不能干净的在最新版本的内核上打上,Linus 是不会接受它的。
9) 不要气馁,继续提交。
当你提交了改动以后,耐心地等待。如果 Linus 喜欢你的改动并且同意它,那么
它将在下一个内核发布版本中出现。
然而,如果你的改动没有出现在下一个版本的内核中,可能有若干原因。减少那
些原因,修正错误,重新提交更新后的改动,是你自己的工作。
Linus不给出任何评论就“丢弃”你的补丁是常见的事情。在系统中这样的事情很
平常。如果他没有接受你的补丁,也许是由于以下原本:
* 你的补丁不能在最新版本的内核上干净的打上。
* 你的补丁在 linux-kernel 邮件列表中没有得到充分的讨论。
* 风格问题(参照第2小节)
* 邮件格式问题(重读本节)
* 你的改动有技术问题。
* 他收到了成吨的 e-mail,而你的在混乱中丢失了。
* 你让人为难。
有疑问的时候,在 linux-kernel 邮件列表上请求评论。
10) 在标题上加上 PATCH 的字样
Linus 和 linux-kernel 邮件列表的 e-mail 流量都很高,一个通常的约定是标
题行以 [PATCH] 开头。这样可以让 Linus 和其他内核开发人员可以从 e-mail
的讨论中很轻易的将补丁分辨出来。
11)为你的工作签名
为了加强对谁做了何事的追踪,尤其是对那些透过好几层的维护者的补丁,我们
建议在发送出去的补丁上加一个 “sign-off” 的过程。
"sign-off" 是在补丁的注释的最后的简单的一行文字,认证你编写了它或者其他
人有权力将它作为开放源代码的补丁传递。规则很简单:如果你能认证如下信息
开发者来源证书 1.1
对于本项目的贡献,我认证如下信息:
(a)这些贡献是完全或者部分的由我创建,我有权利以文件中指出
的开放源代码许可证提交它;或者
(b)这些贡献基于以前的工作,据我所知,这些以前的工作受恰当的开放
源代码许可证保护,而且,根据许可证,我有权提交修改后的贡献,
无论是完全还是部分由我创造,这些贡献都使用同一个开放源代码许可证
(除非我被允许用其它的许可证),正如文件中指出的;或者
(c)这些贡献由认证(a),(b)或者(c)的人直接提供给我,而
且我没有修改它。
(d)我理解并同意这个项目和贡献是公开的,贡献的记录(包括我
一起提交的个人记录,包括 sign-off )被永久维护并且可以和这个项目
或者开放源代码的许可证同步地再发行。
那么加入这样一行:
Signed-off-by: Random J Developer <random@developer.example.org>
使用你的真名(抱歉,不能使用假名或者匿名。)
有人在最后加上标签。现在这些东西会被忽略,但是你可以这样做,来标记公司
内部的过程,或者只是指出关于 sign-off 的一些特殊细节。
12)标准补丁格式
标准的补丁,标题行是:
Subject: [PATCH 001/123] 子系统:一句话概述
标准补丁的信体存在如下部分:
- 一个 "from" 行指出补丁作者。
- 一个空行
- 说明的主体,这些说明文字会被拷贝到描述该补丁的永久改动记录里。
- 一个由"---"构成的标记行
- 不合适放到改动记录里的额外的注解。
- 补丁本身(diff 输出)
标题行的格式,使得对标题行按字母序排序非常的容易 - 很多 e-mail 客户端都
可以支持 - 因为序列号是用零填充的,所以按数字排序和按字母排序是一样的。
e-mail 标题中的“子系统”标识哪个内核子系统将被打补丁。
e-mail 标题中的“一句话概述”扼要的描述 e-mail 中的补丁。“一句话概述”
不应该是一个文件名。对于一个补丁系列(“补丁系列”指一系列的多个相关补
丁),不要对每个补丁都使用同样的“一句话概述”。
记住 e-mail 的“一句话概述”会成为该补丁的全局唯一标识。它会蔓延到 git
的改动记录里。然后“一句话概述”会被用在开发者的讨论里,用来指代这个补
丁。用户将希望通过 google 来搜索"一句话概述"来找到那些讨论这个补丁的文
章。
一些标题的例子:
Subject: [patch 2/5] ext2: improve scalability of bitmap searching
Subject: [PATCHv2 001/207] x86: fix eflags tracking
"from" 行是信体里的最上面一行,具有如下格式:
From: Original Author <author@example.com>
"from" 行指明在永久改动日志里,谁会被确认为作者。如果没有 "from" 行,那
么邮件头里的 "From: " 行会被用来决定改动日志中的作者。
说明的主题将会被提交到永久的源代码改动日志里,因此对那些早已经不记得和
这个补丁相关的讨论细节的有能力的读者来说,是有意义的。
"---" 标记行对于补丁处理工具要找到哪里是改动日志信息的结束,是不可缺少
的。
对于 "---" 标记之后的额外注解,一个好的用途就是用来写 diffstat,用来显
示修改了什么文件和每个文件都增加和删除了多少行。diffstat 对于比较大的补
丁特别有用。其余那些只是和时刻或者开发者相关的注解,不合适放到永久的改
动日志里的,也应该放这里。
使用 diffstat的选项 "-p 1 -w 70" 这样文件名就会从内核源代码树的目录开始
,不会占用太宽的空间(很容易适合80列的宽度,也许会有一些缩进。)
在后面的参考资料中能看到适当的补丁格式的更多细节。
-------------------------------
第二节 提示,建议和诀窍
-------------------------------
本节包含很多和提交到内核的代码有关的通常的"规则"。事情永远有例外...但是
你必须真的有好的理由这样做。你可以把本节叫做Linus的计算机科学入门课。
1) 读 Document/CodingStyle
Nuff 说过,如果你的代码和这个偏离太多,那么它有可能会被拒绝,没有更多的
审查,没有更多的评价。
2) #ifdef 是丑陋的
混杂了 ifdef 的代码难以阅读和维护。别这样做。作为替代,将你的 ifdef 放
在头文件里,有条件地定义 "static inline" 函数,或者宏,在代码里用这些东
西。让编译器把那些"空操作"优化掉。
一个简单的例子,不好的代码:
dev = alloc_etherdev (sizeof(struct funky_private));
if (!dev)
return -ENODEV;
#ifdef CONFIG_NET_FUNKINESS
init_funky_net(dev);
#endif
清理后的例子:
(头文件里)
#ifndef CONFIG_NET_FUNKINESS
static inline void init_funky_net (struct net_device *d) {}
#endif
(代码文件里)
dev = alloc_etherdev (sizeof(struct funky_private));
if (!dev)
return -ENODEV;
init_funky_net(dev);
3) 'static inline' 比宏好
Static inline 函数相比宏来说,是好得多的选择。Static inline 函数提供了
类型安全,没有长度限制,没有格式限制,在 gcc 下开销和宏一样小。
宏只在 static inline 函数不是最优的时候[在 fast paths 里有很少的独立的
案例],或者不可能用 static inline 函数的时候[例如字符串分配]。
应该用 'static inline' 而不是 'static __inline__', 'extern inline' 和
'extern __inline__' 。
4) 不要过度设计
不要试图预计模糊的未来事情,这些事情也许有用也许没有用:"让事情尽可能的
简单,而不是更简单"。
----------------
第三节 参考文献
----------------
Andrew Morton, "The perfect patch" (tpp).
<http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt>
Jeff Garzik, "Linux kernel patch submission format".
<http://linux.yyz.us/patch-format.html>
Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
<http://www.kroah.com/log/2005/03/31/>
<http://www.kroah.com/log/2005/07/08/>
<http://www.kroah.com/log/2005/10/19/>
<http://www.kroah.com/log/2006/01/11/>
NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
<http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2>
Kernel Documentation/CodingStyle:
<http://sosdg.org/~coywolf/lxr/source/Documentation/CodingStyle>
Linus Torvalds's mail on the canonical patch format:
<http://lkml.org/lkml/2005/4/7/183>
--
Chinese translated version of Documentation/oops-tracing.txt
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: Dave Young <hidave.darkstar@gmail.com>
---------------------------------------------------------------------
Documentation/oops-tracing.txt 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 杨瑞 Dave Young <hidave.darkstar@gmail.com>
中文版翻译者: 杨瑞 Dave Young <hidave.darkstar@gmail.com>
中文版校译者: 李阳 Li Yang <leo@zh-kernel.org>
王聪 Wang Cong <xiyou.wangcong@gmail.com>
以下为正文
---------------------------------------------------------------------
注意: ksymoops 在2.6中是没有用的。 请以原有格式使用Oops(来自dmesg,等等)。
忽略任何这样那样关于“解码Oops”或者“通过ksymoops运行”的文档。 如果你贴出运行过
ksymoops的来自2.6的Oops,人们只会让你重贴一次。
快速总结
-------------
发现Oops并发送给看似相关的内核领域的维护者。别太担心对不上号。如果你不确定就发给
和你所做的事情相关的代码的负责人。 如果可重现试着描述怎样重构。 那甚至比oops更有
价值。
如果你对于发送给谁一无所知, 发给linux-kernel@vger.kernel.org。感谢你帮助Linux
尽可能地稳定。
Oops在哪里?
----------------------
通常Oops文本由klogd从内核缓冲区里读取并传给syslogd,由syslogd写到syslog文件中,
典型地是/var/log/messages(依赖于/etc/syslog.conf)。有时klogd崩溃了,这种情况下你
能够运行dmesg > file来从内核缓冲区中读取数据并保存下来。 否则你可以
cat /proc/kmsg > file, 然而你必须介入中止传输, kmsg是一个“永不结束的文件”。如
果机器崩溃坏到你不能输入命令或者磁盘不可用那么你有三种选择:-
(1) 手抄屏幕上的文本待机器重启后再输入计算机。 麻烦但如果没有针对崩溃的准备,
这是仅有的选择。 另外,你可以用数码相机把屏幕拍下来-不太好,但比没有强。 如果信
息滚动到了终端的上面,你会发现以高分辩率启动(比如,vga=791)会让你读到更多的文
本。(注意:这需要vesafb,所以对‘早期’的oops没有帮助)
(2)用串口终端启动(请参看Documentation/serial-console.txt),运行一个null
modem到另一台机器并用你喜欢的通讯工具获取输出。Minicom工作地很好。
(3)使用Kdump(请参看Documentation/kdump/kdump.txt),
使用在Documentation/kdump/gdbmacros.txt中定义的dmesg gdb宏,从旧的内存中提取内核
环形缓冲区。
完整信息
----------------
注意:以下来自于Linus的邮件适用于2.4内核。 我因为历史原因保留了它,并且因为其中
一些信息仍然适用。 特别注意的是,请忽略任何ksymoops的引用。
From: Linus Torvalds <torvalds@osdl.org>
怎样跟踪Oops.. [原发到linux-kernel的一封邮件]
主要的窍门是有五年和这些烦人的oops消息打交道的经验;-)
实际上,你有办法使它更简单。我有两个不同的方法:
gdb /usr/src/linux/vmlinux
gdb> disassemble <offending_function>
那是发现问题的简单办法,至少如果bug报告做的好的情况下(象这个一样-运行ksymoops
得到oops发生的函数及函数内的偏移)。
哦,如果报告发生的内核以相同的编译器和相似的配置编译它会有帮助的。
另一件要做的事是反汇编bug报告的“Code”部分:ksymoops也会用正确的工具来做这件事,
但如果没有那些工具你可以写一个傻程序:
char str[] = "\xXX\xXX\xXX...";
main(){}
并用gcc -g编译它然后执行“disassemble str”(XX部分是由Oops报告的值-你可以仅剪切
粘贴并用“\x”替换空格-我就是这么做的,因为我懒得写程序自动做这一切)。
另外,你可以用scripts/decodecode这个shell脚本。它的使用方法是:
decodecode < oops.txt
“Code”之后的十六进制字节可能(在某些架构上)有一些当前指令之前的指令字节以及
当前和之后的指令字节
Code: f9 0f 8d f9 00 00 00 8d 42 0c e8 dd 26 11 c7 a1 60 ea 2b f9 8b 50 08 a1
64 ea 2b f9 8d 34 82 8b 1e 85 db 74 6d 8b 15 60 ea 2b f9 <8b> 43 04 39 42 54
7e 04 40 89 42 54 8b 43 04 3b 05 00 f6 52 c0
最后,如果你想知道代码来自哪里,你可以:
cd /usr/src/linux
make fs/buffer.s # 或任何产生BUG的文件
然后你会比gdb反汇编更清楚的知道发生了什么。
现在,问题是把你所拥有的所有数据结合起来:C源码(关于它应该怎样的一般知识),
汇编代码及其反汇编得到的代码(另外还有从“oops”消息得到的寄存器状态-对了解毁坏的
指针有用,而且当你有了汇编代码你也能拿其它的寄存器和任何它们对应的C表达式做匹配
)。
实际上,你仅需看看哪里不匹配(这个例子是“Code”反汇编和编译器生成的代码不匹配)。
然后你须要找出为什么不匹配。通常很简单-你看到代码使用了空指针然后你看代码想知道
空指针是怎么出现的,还有检查它是否合法..
现在,如果明白这是一项耗时的工作而且需要一丁点儿的专心,没错。这就是我为什么大多
只是忽略那些没有符号表信息的崩溃报告的原因:简单的说太难查找了(我有一些
程序用于在内核代码段中搜索特定的模式,而且有时我也已经能找出那些崩溃的地方,但是
仅仅是找出正确的序列也确实需要相当扎实的内核知识)
_有时_会发生这种情况,我仅看到崩溃中的反汇编代码序列, 然后我马上就明白问题出在
哪里。这时我才意识到自己干这个工作已经太长时间了;-)
Linus
---------------------------------------------------------------------------
关于Oops跟踪的注解:
为了帮助Linus和其它内核开发者,klogd纳入了大量的支持来处理保护错误。为了拥有对
地址解析的完整支持至少应该使用1.3-pl3的sysklogd包。
当保护错误发生时,klogd守护进程自动把内核日志信息中的重要地址翻译成它们相应的符
号。
klogd执行两种类型的地址解析。首先是静态翻译其次是动态翻译。静态翻译和ksymoops
一样使用System.map文件。为了做静态翻译klogd守护进程必须在初始化时能找到system
map文件。关于klogd怎样搜索map文件请参看klogd手册页。
动态地址翻译在使用内核可装载模块时很重要。 因为内核模块的内存是从内核动态内存池
里分配的,所以不管是模块开始位置还是模块中函数和符号的位置都不是固定的。
内核支持允许程序决定装载哪些模块和它们在内存中位置的系统调用。使用这些系统调用
klogd守护进程生成一张符号表用于调试发生在可装载模块中的保护错误。
至少klogd会提供产生保护错误的模块名。还可有额外的符号信息供可装载模块开发者选择
以从模块中输出符号信息。
因为内核模块环境可能是动态的,所以必须有一种机制当模块环境发生改变时来通知klogd
守护进程。 有一些可用的命令行选项允许klogd向当前执行中的守护进程发送信号,告知符
号信息应该被刷新了。 更多信息请参看klogd手册页。
sysklogd发布时包含一个补丁修改了modules-2.0.0包,无论何时一个模块装载或者卸载都
会自动向klogd发送信号。打上这个补丁提供了必要的对调试发生于内核可装载模块的保护
错误的无缝支持。
以下是被klogd处理过的发生在可装载模块中的一个保护错误例子:
---------------------------------------------------------------------------
Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc
Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000
Aug 29 09:51:01 blizard kernel: *pde = 00000000
Aug 29 09:51:01 blizard kernel: Oops: 0002
Aug 29 09:51:01 blizard kernel: CPU: 0
Aug 29 09:51:01 blizard kernel: EIP: 0010:[oops:_oops+16/3868]
Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212
Aug 29 09:51:01 blizard kernel: eax: 315e97cc ebx: 003a6f80 ecx: 001be77b edx: 00237c0c
Aug 29 09:51:01 blizard kernel: esi: 00000000 edi: bffffdb3 ebp: 00589f90 esp: 00589f8c
Aug 29 09:51:01 blizard kernel: ds: 0018 es: 0018 fs: 002b gs: 002b ss: 0018
Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000)
Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001
Aug 29 09:51:01 blizard kernel: 00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00
Aug 29 09:51:01 blizard kernel: bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036
Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128]
Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3
---------------------------------------------------------------------------
Dr. G.W. Wettstein Oncology Research Div. Computing Facility
Roger Maris Cancer Center INTERNET: greg@wind.rmcc.com
820 4th St. N.
Fargo, ND 58122
Phone: 701-234-7556
---------------------------------------------------------------------------
受污染的内核
一些oops报告在程序记数器之后包含字符串'Tainted: '。这表明内核已经被一些东西给污
染了。 该字符串之后紧跟着一系列的位置敏感的字符,每个代表一个特定的污染值。
1:'G'如果所有装载的模块都有GPL或相容的许可证,'P'如果装载了任何的专有模块。
没有模块MODULE_LICENSE或者带有insmod认为是与GPL不相容的的MODULE_LICENSE的模块被
认定是专有的。
2:'F'如果有任何通过“insmod -f”被强制装载的模块,' '如果所有模块都被正常装载。
3:'S'如果oops发生在SMP内核中,运行于没有证明安全运行多处理器的硬件。 当前这种
情况仅限于几种不支持SMP的速龙处理器。
4:'R'如果模块通过“insmod -f”被强制装载,' '如果所有模块都被正常装载。
5:'M'如果任何处理器报告了机器检查异常,' '如果没有发生机器检查异常。
6:'B'如果页释放函数发现了一个错误的页引用或者一些非预期的页标志。
7:'U'如果用户或者用户应用程序特别请求设置污染标志,否则' '。
8:'D'如果内核刚刚死掉,比如有OOPS或者BUG。
使用'Tainted: '字符串的主要原因是要告诉内核调试者,这是否是一个干净的内核亦或发
生了任何的不正常的事。污染是永久的:即使出错的模块已经被卸载了,污染值仍然存在,
以表明内核不再值得信任。
Chinese translated version of Documentation/sparse.txt
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: Li Yang <leo@zh-kernel.org>
---------------------------------------------------------------------
Documentation/sparse.txt 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 李阳 Li Yang <leo@zh-kernel.org>
中文版翻译者: 李阳 Li Yang <leo@zh-kernel.org>
以下为正文
---------------------------------------------------------------------
Copyright 2004 Linus Torvalds
Copyright 2004 Pavel Machek <pavel@suse.cz>
Copyright 2006 Bob Copeland <me@bobcopeland.com>
使用 sparse 工具做类型检查
~~~~~~~~~~~~~~~~~~~~~~~~~~
"__bitwise" 是一种类型属性,所以你应该这样使用它:
typedef int __bitwise pm_request_t;
enum pm_request {
PM_SUSPEND = (__force pm_request_t) 1,
PM_RESUME = (__force pm_request_t) 2
};
这样会使 PM_SUSPEND 和 PM_RESUME 成为位方式(bitwise)整数(使用"__force"
是因为 sparse 会抱怨改变位方式的类型转换,但是这里我们确实需要强制进行转
换)。而且因为所有枚举值都使用了相同的类型,这里的"enum pm_request"也将
会使用那个类型做为底层实现。
而且使用 gcc 编译的时候,所有的 __bitwise/__force 都会消失,最后在 gcc
看来它们只不过是普通的整数。
坦白来说,你并不需要使用枚举类型。上面那些实际都可以浓缩成一个特殊的"int
__bitwise"类型。
所以更简单的办法只要这样做:
typedef int __bitwise pm_request_t;
#define PM_SUSPEND ((__force pm_request_t) 1)
#define PM_RESUME ((__force pm_request_t) 2)
现在你就有了严格的类型检查所需要的所有基础架构。
一个小提醒:常数整数"0"是特殊的。你可以直接把常数零当作位方式整数使用而
不用担心 sparse 会抱怨。这是因为"bitwise"(恰如其名)是用来确保不同位方
式类型不会被弄混(小尾模式,大尾模式,cpu尾模式,或者其他),对他们来说
常数"0"确实是特殊的。
获取 sparse 工具
~~~~~~~~~~~~~~~~
你可以从 Sparse 的主页获取最新的发布版本:
http://www.kernel.org/pub/linux/kernel/people/josh/sparse/
或者,你也可以使用 git 克隆最新的 sparse 开发版本:
git://git.kernel.org/pub/scm/linux/kernel/git/josh/sparse.git
DaveJ 把每小时自动生成的 git 源码树 tar 包放在以下地址:
http://www.codemonkey.org.uk/projects/git-snapshots/sparse/
一旦你下载了源码,只要以普通用户身份运行:
make
make install
它将会被自动安装到你的 ~/bin 目录下。
使用 sparse 工具
~~~~~~~~~~~~~~~~
用"make C=1"命令来编译内核,会对所有重新编译的 C 文件使用 sparse 工具。
或者使用"make C=2"命令,无论文件是否被重新编译都会对其使用 sparse 工具。
如果你已经编译了内核,用后一种方式可以很快地检查整个源码树。
make 的可选变量 CHECKFLAGS 可以用来向 sparse 工具传递参数。编译系统会自
动向 sparse 工具传递 -Wbitwise 参数。你可以定义 __CHECK_ENDIAN__ 来进行
大小尾检查。
make C=2 CHECKFLAGS="-D__CHECK_ENDIAN__"
这些检查默认都是被关闭的,因为他们通常会产生大量的警告。
Chinese translated version of Documentation/stable_kernel_rules.txt
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: TripleX Chung <triplex@zh-kernel.org>
---------------------------------------------------------------------
Documentation/stable_kernel_rules.txt 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 钟宇 TripleX Chung <triplex@zh-kernel.org>
中文版翻译者: 钟宇 TripleX Chung <triplex@zh-kernel.org>
中文版校译者: 李阳 Li Yang <leo@zh-kernel.org>
Kangkai Yin <e12051@motorola.com>
以下为正文
---------------------------------------------------------------------
关于Linux 2.6稳定版发布,所有你想知道的事情。
关于哪些类型的补丁可以被接收进入稳定版代码树,哪些不可以的规则:
- 必须是显而易见的正确,并且经过测试的。
- 连同上下文,不能大于100行。
- 必须只修正一件事情。
- 必须修正了一个给大家带来麻烦的真正的bug(不是“这也许是一个问题...”
那样的东西)。
- 必须修正带来如下后果的问题:编译错误(对被标记为CONFIG_BROKEN的例外),
内核崩溃,挂起,数据损坏,真正的安全问题,或者一些类似“哦,这不
好”的问题。简短的说,就是一些致命的问题。
- 没有“理论上的竞争条件”,除非能给出竞争条件如何被利用的解释。
- 不能存在任何的“琐碎的”修正(拼写修正,去掉多余空格之类的)。
- 必须被相关子系统的维护者接受。
- 必须遵循Documentation/SubmittingPatches里的规则。
向稳定版代码树提交补丁的过程:
- 在确认了补丁符合以上的规则后,将补丁发送到stable@kernel.org。
- 如果补丁被接受到队列里,发送者会收到一个ACK回复,如果没有被接受,收
到的是NAK回复。回复需要几天的时间,这取决于开发者的时间安排。
- 被接受的补丁会被加到稳定版本队列里,等待其他开发者的审查。
- 安全方面的补丁不要发到这个列表,应该发送到security@kernel.org。
审查周期:
- 当稳定版的维护者决定开始一个审查周期,补丁将被发送到审查委员会,以
及被补丁影响的领域的维护者(除非提交者就是该领域的维护者)并且抄送
到linux-kernel邮件列表。
- 审查委员会有48小时的时间,用来决定给该补丁回复ACK还是NAK。
- 如果委员会中有成员拒绝这个补丁,或者linux-kernel列表上有人反对这个
补丁,并提出维护者和审查委员会之前没有意识到的问题,补丁会从队列中
丢弃。
- 在审查周期结束的时候,那些得到ACK回应的补丁将会被加入到最新的稳定版
发布中,一个新的稳定版发布就此产生。
- 安全性补丁将从内核安全小组那里直接接收到稳定版代码树中,而不是通过
通常的审查周期。请联系内核安全小组以获得关于这个过程的更多细节。
审查委员会:
- 由一些自愿承担这项任务的内核开发者,和几个非志愿的组成。
Chinese translated version of Documentation/volatile-considered-harmful.txt
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.
Maintainer: Jonathan Corbet <corbet@lwn.net>
Chinese maintainer: Bryan Wu <bryan.wu@analog.com>
---------------------------------------------------------------------
Documentation/volatile-considered-harmful.txt 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
英文版维护者: Jonathan Corbet <corbet@lwn.net>
中文版维护者: 伍鹏 Bryan Wu <bryan.wu@analog.com>
中文版翻译者: 伍鹏 Bryan Wu <bryan.wu@analog.com>
中文版校译者: 张汉辉 Eugene Teo <eugeneteo@kernel.sg>
杨瑞 Dave Young <hidave.darkstar@gmail.com>
以下为正文
---------------------------------------------------------------------
为什么不应该使用“volatile”类型
------------------------------
C程序员通常认为volatile表示某个变量可以在当前执行的线程之外被改变;因此,在内核
中用到共享数据结构时,常常会有C程序员喜欢使用volatile这类变量。换句话说,他们经
常会把volatile类型看成某种简易的原子变量,当然它们不是。在内核中使用volatile几
乎总是错误的;本文档将解释为什么这样。
理解volatile的关键是知道它的目的是用来消除优化,实际上很少有人真正需要这样的应
用。在内核中,程序员必须防止意外的并发访问破坏共享的数据结构,这其实是一个完全
不同的任务。用来防止意外并发访问的保护措施,可以更加高效的避免大多数优化相关的
问题。
像volatile一样,内核提供了很多原语来保证并发访问时的数据安全(自旋锁, 互斥量,内
存屏障等等),同样可以防止意外的优化。如果可以正确使用这些内核原语,那么就没有
必要再使用volatile。如果仍然必须使用volatile,那么几乎可以肯定在代码的某处有一
个bug。在正确设计的内核代码中,volatile能带来的仅仅是使事情变慢。
思考一下这段典型的内核代码:
spin_lock(&the_lock);
do_something_on(&shared_data);
do_something_else_with(&shared_data);
spin_unlock(&the_lock);
如果所有的代码都遵循加锁规则,当持有the_lock的时候,不可能意外的改变shared_data的
值。任何可能访问该数据的其他代码都会在这个锁上等待。自旋锁原语跟内存屏障一样—— 它
们显式的用来书写成这样 —— 意味着数据访问不会跨越它们而被优化。所以本来编译器认为
它知道在shared_data里面将有什么,但是因为spin_lock()调用跟内存屏障一样,会强制编
译器忘记它所知道的一切。那么在访问这些数据时不会有优化的问题。
如果shared_data被声名为volatile,锁操作将仍然是必须的。就算我们知道没有其他人正在
使用它,编译器也将被阻止优化对临界区内shared_data的访问。在锁有效的同时,
shared_data不是volatile的。在处理共享数据的时候,适当的锁操作可以不再需要
volatile —— 并且是有潜在危害的。
volatile的存储类型最初是为那些内存映射的I/O寄存器而定义。在内核里,寄存器访问也应
该被锁保护,但是人们也不希望编译器“优化”临界区内的寄存器访问。内核里I/O的内存访问
是通过访问函数完成的;不赞成通过指针对I/O内存的直接访问,并且不是在所有体系架构上
都能工作。那些访问函数正是为了防止意外优化而写的,因此,再说一次,volatile类型不
是必需的。
另一种引起用户可能使用volatile的情况是当处理器正忙着等待一个变量的值。正确执行一
个忙等待的方法是:
while (my_variable != what_i_want)
cpu_relax();
cpu_relax()调用会降低CPU的能量消耗或者让位于超线程双处理器;它也作为内存屏障一样出
现,所以,再一次,volatile不是必需的。当然,忙等待一开始就是一种反常规的做法。
在内核中,一些稀少的情况下volatile仍然是有意义的:
- 在一些体系架构的系统上,允许直接的I/0内存访问,那么前面提到的访问函数可以使用
volatile。基本上,每一个访问函数调用它自己都是一个小的临界区域并且保证了按照
程序员期望的那样发生访问操作。
- 某些会改变内存的内联汇编代码虽然没有什么其他明显的附作用,但是有被GCC删除的可
能性。在汇编声明中加上volatile关键字可以防止这种删除操作。
- Jiffies变量是一种特殊情况,虽然每次引用它的时候都可以有不同的值,但读jiffies
变量时不需要任何特殊的加锁保护。所以jiffies变量可以使用volatile,但是不赞成
其他跟jiffies相同类型变量使用volatile。Jiffies被认为是一种“愚蠢的遗留物"
(Linus的话)因为解决这个问题比保持现状要麻烦的多。
- 由于某些I/0设备可能会修改连续一致的内存,所以有时,指向连续一致内存的数据结构
的指针需要正确的使用volatile。网络适配器使用的环状缓存区正是这类情形的一个例
子,其中适配器用改变指针来表示哪些描述符已经处理过了。
对于大多代码,上述几种可以使用volatile的情况都不适用。所以,使用volatile是一种
bug并且需要对这样的代码额外仔细检查。那些试图使用volatile的开发人员需要退一步想想
他们真正想实现的是什么。
非常欢迎删除volatile变量的补丁 - 只要证明这些补丁完整的考虑了并发问题。
注释
----
[1] http://lwn.net/Articles/233481/
[2] http://lwn.net/Articles/233482/
致谢
----
最初由Randy Dunlap推动并作初步研究
由Jonathan Corbet撰写
参考Satyam Sharma,Johannes Stezenbach,Jesper Juhl,Heikki Orsila,
H. Peter Anvin,Philipp Hahn和Stefan Richter的意见改善了本档。
...@@ -195,7 +195,7 @@ static int leds_shutdown(struct sys_device *dev) ...@@ -195,7 +195,7 @@ static int leds_shutdown(struct sys_device *dev)
} }
static struct sysdev_class leds_sysclass = { static struct sysdev_class leds_sysclass = {
set_kset_name("leds"), .name = "leds",
.shutdown = leds_shutdown, .shutdown = leds_shutdown,
.suspend = leds_suspend, .suspend = leds_suspend,
.resume = leds_resume, .resume = leds_resume,
...@@ -369,7 +369,7 @@ static int timer_resume(struct sys_device *dev) ...@@ -369,7 +369,7 @@ static int timer_resume(struct sys_device *dev)
#endif #endif
static struct sysdev_class timer_sysclass = { static struct sysdev_class timer_sysclass = {
set_kset_name("timer"), .name = "timer",
.suspend = timer_suspend, .suspend = timer_suspend,
.resume = timer_resume, .resume = timer_resume,
}; };
......
...@@ -214,7 +214,7 @@ static int irq_resume(struct sys_device *dev) ...@@ -214,7 +214,7 @@ static int irq_resume(struct sys_device *dev)
#endif #endif
static struct sysdev_class irq_class = { static struct sysdev_class irq_class = {
set_kset_name("irq"), .name = "irq",
.suspend = irq_suspend, .suspend = irq_suspend,
.resume = irq_resume, .resume = irq_resume,
}; };
......
...@@ -69,14 +69,14 @@ static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE]; ...@@ -69,14 +69,14 @@ static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
static unsigned short enable_dyn_sleep = 1; static unsigned short enable_dyn_sleep = 1;
static ssize_t omap_pm_sleep_while_idle_show(struct kset *kset, char *buf) static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{ {
return sprintf(buf, "%hu\n", enable_dyn_sleep); return sprintf(buf, "%hu\n", enable_dyn_sleep);
} }
static ssize_t omap_pm_sleep_while_idle_store(struct kset *kset, static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
const char * buf, const char * buf, size_t n)
size_t n)
{ {
unsigned short value; unsigned short value;
if (sscanf(buf, "%hu", &value) != 1 || if (sscanf(buf, "%hu", &value) != 1 ||
...@@ -88,16 +88,9 @@ static ssize_t omap_pm_sleep_while_idle_store(struct kset *kset, ...@@ -88,16 +88,9 @@ static ssize_t omap_pm_sleep_while_idle_store(struct kset *kset,
return n; return n;
} }
static struct subsys_attribute sleep_while_idle_attr = { static struct kobj_attribute sleep_while_idle_attr =
.attr = { __ATTR(sleep_while_idle, 0644, idle_show, idle_store);
.name = __stringify(sleep_while_idle),
.mode = 0644,
},
.show = omap_pm_sleep_while_idle_show,
.store = omap_pm_sleep_while_idle_store,
};
extern struct kset power_subsys;
static void (*omap_sram_idle)(void) = NULL; static void (*omap_sram_idle)(void) = NULL;
static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL; static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
...@@ -726,9 +719,9 @@ static int __init omap_pm_init(void) ...@@ -726,9 +719,9 @@ static int __init omap_pm_init(void)
omap_pm_init_proc(); omap_pm_init_proc();
#endif #endif
error = subsys_create_file(&power_subsys, &sleep_while_idle_attr); error = sysfs_create_file(power_kobj, &sleep_while_idle_attr);
if (error) if (error)
printk(KERN_ERR "subsys_create_file failed: %d\n", error); printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
if (cpu_is_omap16xx()) { if (cpu_is_omap16xx()) {
/* configure LOW_PWR pin */ /* configure LOW_PWR pin */
......
...@@ -566,7 +566,7 @@ static int cmx270_resume(struct sys_device *dev) ...@@ -566,7 +566,7 @@ static int cmx270_resume(struct sys_device *dev)
} }
static struct sysdev_class cmx270_pm_sysclass = { static struct sysdev_class cmx270_pm_sysclass = {
set_kset_name("pm"), .name = "pm",
.resume = cmx270_resume, .resume = cmx270_resume,
.suspend = cmx270_suspend, .suspend = cmx270_suspend,
}; };
......
...@@ -122,7 +122,7 @@ static int lpd270_irq_resume(struct sys_device *dev) ...@@ -122,7 +122,7 @@ static int lpd270_irq_resume(struct sys_device *dev)
} }
static struct sysdev_class lpd270_irq_sysclass = { static struct sysdev_class lpd270_irq_sysclass = {
set_kset_name("cpld_irq"), .name = "cpld_irq",
.resume = lpd270_irq_resume, .resume = lpd270_irq_resume,
}; };
......
...@@ -126,7 +126,7 @@ static int lubbock_irq_resume(struct sys_device *dev) ...@@ -126,7 +126,7 @@ static int lubbock_irq_resume(struct sys_device *dev)
} }
static struct sysdev_class lubbock_irq_sysclass = { static struct sysdev_class lubbock_irq_sysclass = {
set_kset_name("cpld_irq"), .name = "cpld_irq",
.resume = lubbock_irq_resume, .resume = lubbock_irq_resume,
}; };
......
...@@ -120,7 +120,7 @@ static int mainstone_irq_resume(struct sys_device *dev) ...@@ -120,7 +120,7 @@ static int mainstone_irq_resume(struct sys_device *dev)
} }
static struct sysdev_class mainstone_irq_sysclass = { static struct sysdev_class mainstone_irq_sysclass = {
set_kset_name("cpld_irq"), .name = "cpld_irq",
.resume = mainstone_irq_resume, .resume = mainstone_irq_resume,
}; };
......
...@@ -100,7 +100,7 @@ void __init s3c2410_init_clocks(int xtal) ...@@ -100,7 +100,7 @@ void __init s3c2410_init_clocks(int xtal)
} }
struct sysdev_class s3c2410_sysclass = { struct sysdev_class s3c2410_sysclass = {
set_kset_name("s3c2410-core"), .name = "s3c2410-core",
}; };
static struct sys_device s3c2410_sysdev = { static struct sys_device s3c2410_sysdev = {
......
...@@ -196,7 +196,7 @@ void __init s3c2412_init_clocks(int xtal) ...@@ -196,7 +196,7 @@ void __init s3c2412_init_clocks(int xtal)
*/ */
struct sysdev_class s3c2412_sysclass = { struct sysdev_class s3c2412_sysclass = {
set_kset_name("s3c2412-core"), .name = "s3c2412-core",
}; };
static int __init s3c2412_core_init(void) static int __init s3c2412_core_init(void)
......
...@@ -312,7 +312,7 @@ static int osiris_pm_resume(struct sys_device *sd) ...@@ -312,7 +312,7 @@ static int osiris_pm_resume(struct sys_device *sd)
#endif #endif
static struct sysdev_class osiris_pm_sysclass = { static struct sysdev_class osiris_pm_sysclass = {
set_kset_name("mach-osiris"), .name = "mach-osiris",
.suspend = osiris_pm_suspend, .suspend = osiris_pm_suspend,
.resume = osiris_pm_resume, .resume = osiris_pm_resume,
}; };
......
...@@ -43,7 +43,7 @@ static struct map_desc s3c2443_iodesc[] __initdata = { ...@@ -43,7 +43,7 @@ static struct map_desc s3c2443_iodesc[] __initdata = {
}; };
struct sysdev_class s3c2443_sysclass = { struct sysdev_class s3c2443_sysclass = {
set_kset_name("s3c2443-core"), .name = "s3c2443-core",
}; };
static struct sys_device s3c2443_sysdev = { static struct sys_device s3c2443_sysdev = {
......
...@@ -283,7 +283,7 @@ static int sa1100irq_resume(struct sys_device *dev) ...@@ -283,7 +283,7 @@ static int sa1100irq_resume(struct sys_device *dev)
} }
static struct sysdev_class sa1100irq_sysclass = { static struct sysdev_class sa1100irq_sysclass = {
set_kset_name("sa11x0-irq"), .name = "sa11x0-irq",
.suspend = sa1100irq_suspend, .suspend = sa1100irq_suspend,
.resume = sa1100irq_resume, .resume = sa1100irq_resume,
}; };
......
...@@ -96,7 +96,7 @@ static int op_arm_resume(struct sys_device *dev) ...@@ -96,7 +96,7 @@ static int op_arm_resume(struct sys_device *dev)
} }
static struct sysdev_class oprofile_sysclass = { static struct sysdev_class oprofile_sysclass = {
set_kset_name("oprofile"), .name = "oprofile",
.resume = op_arm_resume, .resume = op_arm_resume,
.suspend = op_arm_suspend, .suspend = op_arm_suspend,
}; };
......
...@@ -1455,7 +1455,7 @@ static int omap_gpio_resume(struct sys_device *dev) ...@@ -1455,7 +1455,7 @@ static int omap_gpio_resume(struct sys_device *dev)
} }
static struct sysdev_class omap_gpio_sysclass = { static struct sysdev_class omap_gpio_sysclass = {
set_kset_name("gpio"), .name = "gpio",
.suspend = omap_gpio_suspend, .suspend = omap_gpio_suspend,
.resume = omap_gpio_resume, .resume = omap_gpio_resume,
}; };
......
...@@ -1265,7 +1265,7 @@ static int s3c2410_dma_resume(struct sys_device *dev) ...@@ -1265,7 +1265,7 @@ static int s3c2410_dma_resume(struct sys_device *dev)
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
struct sysdev_class dma_sysclass = { struct sysdev_class dma_sysclass = {
set_kset_name("s3c24xx-dma"), .name = "s3c24xx-dma",
.suspend = s3c2410_dma_suspend, .suspend = s3c2410_dma_suspend,
.resume = s3c2410_dma_resume, .resume = s3c2410_dma_resume,
}; };
......
...@@ -151,13 +151,13 @@ static int s3c244x_resume(struct sys_device *dev) ...@@ -151,13 +151,13 @@ static int s3c244x_resume(struct sys_device *dev)
/* Since the S3C2442 and S3C2440 share items, put both sysclasses here */ /* Since the S3C2442 and S3C2440 share items, put both sysclasses here */
struct sysdev_class s3c2440_sysclass = { struct sysdev_class s3c2440_sysclass = {
set_kset_name("s3c2440-core"), .name = "s3c2440-core",
.suspend = s3c244x_suspend, .suspend = s3c244x_suspend,
.resume = s3c244x_resume .resume = s3c244x_resume
}; };
struct sysdev_class s3c2442_sysclass = { struct sysdev_class s3c2442_sysclass = {
set_kset_name("s3c2442-core"), .name = "s3c2442-core",
.suspend = s3c244x_suspend, .suspend = s3c244x_suspend,
.resume = s3c244x_resume .resume = s3c244x_resume
}; };
......
...@@ -214,7 +214,7 @@ void __init time_init(void) ...@@ -214,7 +214,7 @@ void __init time_init(void)
} }
static struct sysdev_class timer_class = { static struct sysdev_class timer_class = {
set_kset_name("timer"), .name = "timer",
}; };
static struct sys_device timer_device = { static struct sys_device timer_device = {
......
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
#define IOP_TIMEOUT 100 #define IOP_TIMEOUT 100
#error "This driver is broken with regard to its driver core usage."
#error "Please contact <greg@kroah.com> for details on how to fix it properly."
static struct device iop_spu_device[2] = { static struct device iop_spu_device[2] = {
{ .bus_id = "iop-spu0", }, { .bus_id = "iop-spu0", },
{ .bus_id = "iop-spu1", }, { .bus_id = "iop-spu1", },
...@@ -192,6 +195,13 @@ int iop_start_mpu(unsigned int start_addr) ...@@ -192,6 +195,13 @@ int iop_start_mpu(unsigned int start_addr)
static int __init iop_fw_load_init(void) static int __init iop_fw_load_init(void)
{ {
#if 0
/*
* static struct devices can not be added directly to sysfs by ignoring
* the driver model infrastructure. To fix this properly, please use
* the platform_bus to register these devices to be able to properly
* use the firmware infrastructure.
*/
device_initialize(&iop_spu_device[0]); device_initialize(&iop_spu_device[0]);
kobject_set_name(&iop_spu_device[0].kobj, "iop-spu0"); kobject_set_name(&iop_spu_device[0].kobj, "iop-spu0");
kobject_add(&iop_spu_device[0].kobj); kobject_add(&iop_spu_device[0].kobj);
...@@ -201,6 +211,7 @@ static int __init iop_fw_load_init(void) ...@@ -201,6 +211,7 @@ static int __init iop_fw_load_init(void)
device_initialize(&iop_mpu_device); device_initialize(&iop_mpu_device);
kobject_set_name(&iop_mpu_device.kobj, "iop-mpu"); kobject_set_name(&iop_mpu_device.kobj, "iop-mpu");
kobject_add(&iop_mpu_device.kobj); kobject_add(&iop_mpu_device.kobj);
#endif
return 0; return 0;
} }
......
...@@ -354,27 +354,27 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) ...@@ -354,27 +354,27 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
if (unlikely(retval < 0)) if (unlikely(retval < 0))
return retval; return retval;
all_cpu_cache_info[cpu].kobj.parent = &sys_dev->kobj; retval = kobject_init_and_add(&all_cpu_cache_info[cpu].kobj,
kobject_set_name(&all_cpu_cache_info[cpu].kobj, "%s", "cache"); &cache_ktype_percpu_entry, &sys_dev->kobj,
all_cpu_cache_info[cpu].kobj.ktype = &cache_ktype_percpu_entry; "%s", "cache");
retval = kobject_register(&all_cpu_cache_info[cpu].kobj);
for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) { for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) {
this_object = LEAF_KOBJECT_PTR(cpu,i); this_object = LEAF_KOBJECT_PTR(cpu,i);
this_object->kobj.parent = &all_cpu_cache_info[cpu].kobj; retval = kobject_init_and_add(&(this_object->kobj),
kobject_set_name(&(this_object->kobj), "index%1lu", i); &cache_ktype,
this_object->kobj.ktype = &cache_ktype; &all_cpu_cache_info[cpu].kobj,
retval = kobject_register(&(this_object->kobj)); "index%1lu", i);
if (unlikely(retval)) { if (unlikely(retval)) {
for (j = 0; j < i; j++) { for (j = 0; j < i; j++) {
kobject_unregister( kobject_put(&(LEAF_KOBJECT_PTR(cpu,j)->kobj));
&(LEAF_KOBJECT_PTR(cpu,j)->kobj));
} }
kobject_unregister(&all_cpu_cache_info[cpu].kobj); kobject_put(&all_cpu_cache_info[cpu].kobj);
cpu_cache_sysfs_exit(cpu); cpu_cache_sysfs_exit(cpu);
break; break;
} }
kobject_uevent(&(this_object->kobj), KOBJ_ADD);
} }
kobject_uevent(&all_cpu_cache_info[cpu].kobj, KOBJ_ADD);
return retval; return retval;
} }
...@@ -385,10 +385,10 @@ static int __cpuinit cache_remove_dev(struct sys_device * sys_dev) ...@@ -385,10 +385,10 @@ static int __cpuinit cache_remove_dev(struct sys_device * sys_dev)
unsigned long i; unsigned long i;
for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++)
kobject_unregister(&(LEAF_KOBJECT_PTR(cpu,i)->kobj)); kobject_put(&(LEAF_KOBJECT_PTR(cpu,i)->kobj));
if (all_cpu_cache_info[cpu].kobj.parent) { if (all_cpu_cache_info[cpu].kobj.parent) {
kobject_unregister(&all_cpu_cache_info[cpu].kobj); kobject_put(&all_cpu_cache_info[cpu].kobj);
memset(&all_cpu_cache_info[cpu].kobj, memset(&all_cpu_cache_info[cpu].kobj,
0, 0,
sizeof(struct kobject)); sizeof(struct kobject));
......
...@@ -238,7 +238,7 @@ static int i8259A_shutdown(struct sys_device *dev) ...@@ -238,7 +238,7 @@ static int i8259A_shutdown(struct sys_device *dev)
} }
static struct sysdev_class i8259_sysdev_class = { static struct sysdev_class i8259_sysdev_class = {
set_kset_name("i8259"), .name = "i8259",
.resume = i8259A_resume, .resume = i8259A_resume,
.shutdown = i8259A_shutdown, .shutdown = i8259A_shutdown,
}; };
......
...@@ -459,7 +459,7 @@ static int spu_shutdown(struct sys_device *sysdev) ...@@ -459,7 +459,7 @@ static int spu_shutdown(struct sys_device *sysdev)
} }
static struct sysdev_class spu_sysdev_class = { static struct sysdev_class spu_sysdev_class = {
set_kset_name("spu"), .name = "spu",
.shutdown = spu_shutdown, .shutdown = spu_shutdown,
}; };
......
...@@ -663,7 +663,7 @@ static int pmacpic_resume(struct sys_device *sysdev) ...@@ -663,7 +663,7 @@ static int pmacpic_resume(struct sys_device *sysdev)
#endif /* CONFIG_PM && CONFIG_PPC32 */ #endif /* CONFIG_PM && CONFIG_PPC32 */
static struct sysdev_class pmacpic_sysclass = { static struct sysdev_class pmacpic_sysclass = {
set_kset_name("pmac_pic"), .name = "pmac_pic",
}; };
static struct sys_device device_pmacpic = { static struct sys_device device_pmacpic = {
......
...@@ -28,13 +28,15 @@ ...@@ -28,13 +28,15 @@
unsigned long rtas_poweron_auto; /* default and normal state is 0 */ unsigned long rtas_poweron_auto; /* default and normal state is 0 */
static ssize_t auto_poweron_show(struct kset *kset, char *buf) static ssize_t auto_poweron_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{ {
return sprintf(buf, "%lu\n", rtas_poweron_auto); return sprintf(buf, "%lu\n", rtas_poweron_auto);
} }
static ssize_t static ssize_t auto_poweron_store(struct kobject *kobj,
auto_poweron_store(struct kset *kset, const char *buf, size_t n) struct kobj_attribute *attr,
const char *buf, size_t n)
{ {
int ret; int ret;
unsigned long ups_restart; unsigned long ups_restart;
...@@ -47,17 +49,11 @@ auto_poweron_store(struct kset *kset, const char *buf, size_t n) ...@@ -47,17 +49,11 @@ auto_poweron_store(struct kset *kset, const char *buf, size_t n)
return -EINVAL; return -EINVAL;
} }
static struct subsys_attribute auto_poweron_attr = { static struct kobj_attribute auto_poweron_attr =
.attr = { __ATTR(auto_poweron, 0644, auto_poweron_show, auto_poweron_store);
.name = __stringify(auto_poweron),
.mode = 0644,
},
.show = auto_poweron_show,
.store = auto_poweron_store,
};
#ifndef CONFIG_PM #ifndef CONFIG_PM
decl_subsys(power,NULL,NULL); struct kobject *power_kobj;
static struct attribute *g[] = { static struct attribute *g[] = {
&auto_poweron_attr.attr, &auto_poweron_attr.attr,
...@@ -70,18 +66,16 @@ static struct attribute_group attr_group = { ...@@ -70,18 +66,16 @@ static struct attribute_group attr_group = {
static int __init pm_init(void) static int __init pm_init(void)
{ {
int error = subsystem_register(&power_subsys); power_kobj = kobject_create_and_add("power", NULL);
if (!error) if (!power_kobj)
error = sysfs_create_group(&power_subsys.kobj, &attr_group); return -ENOMEM;
return error; return sysfs_create_group(power_kobj, &attr_group);
} }
core_initcall(pm_init); core_initcall(pm_init);
#else #else
extern struct kset power_subsys;
static int __init apo_pm_init(void) static int __init apo_pm_init(void)
{ {
return (subsys_create_file(&power_subsys, &auto_poweron_attr)); return (sysfs_create_file(power_kobj, &auto_poweron_attr));
} }
__initcall(apo_pm_init); __initcall(apo_pm_init);
#endif #endif
...@@ -725,7 +725,7 @@ unsigned int ipic_get_irq(void) ...@@ -725,7 +725,7 @@ unsigned int ipic_get_irq(void)
} }
static struct sysdev_class ipic_sysclass = { static struct sysdev_class ipic_sysclass = {
set_kset_name("ipic"), .name = "ipic",
}; };
static struct sys_device device_ipic = { static struct sys_device device_ipic = {
......
...@@ -1584,7 +1584,7 @@ static struct sysdev_class mpic_sysclass = { ...@@ -1584,7 +1584,7 @@ static struct sysdev_class mpic_sysclass = {
.resume = mpic_resume, .resume = mpic_resume,
.suspend = mpic_suspend, .suspend = mpic_suspend,
#endif #endif
set_kset_name("mpic"), .name = "mpic",
}; };
static int mpic_init_sys(void) static int mpic_init_sys(void)
......
...@@ -483,7 +483,7 @@ int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high) ...@@ -483,7 +483,7 @@ int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high)
} }
static struct sysdev_class qe_ic_sysclass = { static struct sysdev_class qe_ic_sysclass = {
set_kset_name("qe_ic"), .name = "qe_ic",
}; };
static struct sys_device device_qe_ic = { static struct sys_device device_qe_ic = {
......
...@@ -614,7 +614,7 @@ int ipic_get_irq(void) ...@@ -614,7 +614,7 @@ int ipic_get_irq(void)
} }
static struct sysdev_class ipic_sysclass = { static struct sysdev_class ipic_sysclass = {
set_kset_name("ipic"), .name = "ipic",
}; };
static struct sys_device device_ipic = { static struct sys_device device_ipic = {
......
...@@ -1043,7 +1043,7 @@ int openpic_resume(struct sys_device *sysdev) ...@@ -1043,7 +1043,7 @@ int openpic_resume(struct sys_device *sysdev)
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
static struct sysdev_class openpic_sysclass = { static struct sysdev_class openpic_sysclass = {
set_kset_name("openpic"), .name = "openpic",
}; };
static struct sys_device device_openpic = { static struct sys_device device_openpic = {
......
...@@ -666,7 +666,7 @@ int openpic2_resume(struct sys_device *sysdev) ...@@ -666,7 +666,7 @@ int openpic2_resume(struct sys_device *sysdev)
/* HACK ALERT */ /* HACK ALERT */
static struct sysdev_class openpic2_sysclass = { static struct sysdev_class openpic2_sysclass = {
set_kset_name("openpic2"), .name = "openpic2",
}; };
static struct sys_device device_openpic2 = { static struct sys_device device_openpic2 = {
......
...@@ -490,7 +490,7 @@ static struct super_operations hypfs_s_ops = { ...@@ -490,7 +490,7 @@ static struct super_operations hypfs_s_ops = {
.show_options = hypfs_show_options, .show_options = hypfs_show_options,
}; };
static decl_subsys(s390, NULL, NULL); static struct kobject *s390_kobj;
static int __init hypfs_init(void) static int __init hypfs_init(void)
{ {
...@@ -506,17 +506,18 @@ static int __init hypfs_init(void) ...@@ -506,17 +506,18 @@ static int __init hypfs_init(void)
goto fail_diag; goto fail_diag;
} }
} }
kobj_set_kset_s(&s390_subsys, hypervisor_subsys); s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
rc = subsystem_register(&s390_subsys); if (!s390_kobj) {
if (rc) rc = -ENOMEM;;
goto fail_sysfs; goto fail_sysfs;
}
rc = register_filesystem(&hypfs_type); rc = register_filesystem(&hypfs_type);
if (rc) if (rc)
goto fail_filesystem; goto fail_filesystem;
return 0; return 0;
fail_filesystem: fail_filesystem:
subsystem_unregister(&s390_subsys); kobject_put(s390_kobj);
fail_sysfs: fail_sysfs:
if (!MACHINE_IS_VM) if (!MACHINE_IS_VM)
hypfs_diag_exit(); hypfs_diag_exit();
...@@ -530,7 +531,7 @@ static void __exit hypfs_exit(void) ...@@ -530,7 +531,7 @@ static void __exit hypfs_exit(void)
if (!MACHINE_IS_VM) if (!MACHINE_IS_VM)
hypfs_diag_exit(); hypfs_diag_exit();
unregister_filesystem(&hypfs_type); unregister_filesystem(&hypfs_type);
subsystem_unregister(&s390_subsys); kobject_put(s390_kobj);
} }
module_init(hypfs_init) module_init(hypfs_init)
......
...@@ -162,22 +162,25 @@ EXPORT_SYMBOL_GPL(diag308); ...@@ -162,22 +162,25 @@ EXPORT_SYMBOL_GPL(diag308);
/* SYSFS */ /* SYSFS */
#define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \ #define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \
static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset, \ static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj, \
struct kobj_attribute *attr, \
char *page) \ char *page) \
{ \ { \
return sprintf(page, _format, _value); \ return sprintf(page, _format, _value); \
} \ } \
static struct subsys_attribute sys_##_prefix##_##_name##_attr = \ static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
__ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL); __ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL);
#define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value) \ #define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value) \
static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset, \ static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj, \
struct kobj_attribute *attr, \
char *page) \ char *page) \
{ \ { \
return sprintf(page, _fmt_out, \ return sprintf(page, _fmt_out, \
(unsigned long long) _value); \ (unsigned long long) _value); \
} \ } \
static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset, \ static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
struct kobj_attribute *attr, \
const char *buf, size_t len) \ const char *buf, size_t len) \
{ \ { \
unsigned long long value; \ unsigned long long value; \
...@@ -186,25 +189,27 @@ static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset, \ ...@@ -186,25 +189,27 @@ static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset, \
_value = value; \ _value = value; \
return len; \ return len; \
} \ } \
static struct subsys_attribute sys_##_prefix##_##_name##_attr = \ static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
__ATTR(_name,(S_IRUGO | S_IWUSR), \ __ATTR(_name,(S_IRUGO | S_IWUSR), \
sys_##_prefix##_##_name##_show, \ sys_##_prefix##_##_name##_show, \
sys_##_prefix##_##_name##_store); sys_##_prefix##_##_name##_store);
#define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\ #define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset, \ static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj, \
struct kobj_attribute *attr, \
char *page) \ char *page) \
{ \ { \
return sprintf(page, _fmt_out, _value); \ return sprintf(page, _fmt_out, _value); \
} \ } \
static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset, \ static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
struct kobj_attribute *attr, \
const char *buf, size_t len) \ const char *buf, size_t len) \
{ \ { \
if (sscanf(buf, _fmt_in, _value) != 1) \ if (sscanf(buf, _fmt_in, _value) != 1) \
return -EINVAL; \ return -EINVAL; \
return len; \ return len; \
} \ } \
static struct subsys_attribute sys_##_prefix##_##_name##_attr = \ static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
__ATTR(_name,(S_IRUGO | S_IWUSR), \ __ATTR(_name,(S_IRUGO | S_IWUSR), \
sys_##_prefix##_##_name##_show, \ sys_##_prefix##_##_name##_show, \
sys_##_prefix##_##_name##_store); sys_##_prefix##_##_name##_store);
...@@ -270,14 +275,16 @@ void __init setup_ipl_info(void) ...@@ -270,14 +275,16 @@ void __init setup_ipl_info(void)
struct ipl_info ipl_info; struct ipl_info ipl_info;
EXPORT_SYMBOL_GPL(ipl_info); EXPORT_SYMBOL_GPL(ipl_info);
static ssize_t ipl_type_show(struct kset *kset, char *page) static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr,
char *page)
{ {
return sprintf(page, "%s\n", ipl_type_str(ipl_info.type)); return sprintf(page, "%s\n", ipl_type_str(ipl_info.type));
} }
static struct subsys_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
static ssize_t sys_ipl_device_show(struct kset *kset, char *page) static ssize_t sys_ipl_device_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
{ {
struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START; struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
...@@ -292,7 +299,7 @@ static ssize_t sys_ipl_device_show(struct kset *kset, char *page) ...@@ -292,7 +299,7 @@ static ssize_t sys_ipl_device_show(struct kset *kset, char *page)
} }
} }
static struct subsys_attribute sys_ipl_device_attr = static struct kobj_attribute sys_ipl_device_attr =
__ATTR(device, S_IRUGO, sys_ipl_device_show, NULL); __ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr, static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr,
...@@ -367,7 +374,8 @@ static struct attribute_group ipl_fcp_attr_group = { ...@@ -367,7 +374,8 @@ static struct attribute_group ipl_fcp_attr_group = {
/* CCW ipl device attributes */ /* CCW ipl device attributes */
static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page) static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
{ {
char loadparm[LOADPARM_LEN + 1] = {}; char loadparm[LOADPARM_LEN + 1] = {};
...@@ -379,7 +387,7 @@ static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page) ...@@ -379,7 +387,7 @@ static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page)
return sprintf(page, "%s\n", loadparm); return sprintf(page, "%s\n", loadparm);
} }
static struct subsys_attribute sys_ipl_ccw_loadparm_attr = static struct kobj_attribute sys_ipl_ccw_loadparm_attr =
__ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL); __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
static struct attribute *ipl_ccw_attrs[] = { static struct attribute *ipl_ccw_attrs[] = {
...@@ -418,7 +426,7 @@ static struct attribute_group ipl_unknown_attr_group = { ...@@ -418,7 +426,7 @@ static struct attribute_group ipl_unknown_attr_group = {
.attrs = ipl_unknown_attrs, .attrs = ipl_unknown_attrs,
}; };
static decl_subsys(ipl, NULL, NULL); static struct kset *ipl_kset;
/* /*
* reipl section * reipl section
...@@ -465,7 +473,8 @@ static void reipl_get_ascii_loadparm(char *loadparm) ...@@ -465,7 +473,8 @@ static void reipl_get_ascii_loadparm(char *loadparm)
strstrip(loadparm); strstrip(loadparm);
} }
static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page) static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
{ {
char buf[LOADPARM_LEN + 1]; char buf[LOADPARM_LEN + 1];
...@@ -473,7 +482,8 @@ static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page) ...@@ -473,7 +482,8 @@ static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page)
return sprintf(page, "%s\n", buf); return sprintf(page, "%s\n", buf);
} }
static ssize_t reipl_ccw_loadparm_store(struct kset *kset, static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t len) const char *buf, size_t len)
{ {
int i, lp_len; int i, lp_len;
...@@ -500,7 +510,7 @@ static ssize_t reipl_ccw_loadparm_store(struct kset *kset, ...@@ -500,7 +510,7 @@ static ssize_t reipl_ccw_loadparm_store(struct kset *kset,
return len; return len;
} }
static struct subsys_attribute sys_reipl_ccw_loadparm_attr = static struct kobj_attribute sys_reipl_ccw_loadparm_attr =
__ATTR(loadparm, 0644, reipl_ccw_loadparm_show, __ATTR(loadparm, 0644, reipl_ccw_loadparm_show,
reipl_ccw_loadparm_store); reipl_ccw_loadparm_store);
...@@ -568,13 +578,15 @@ static int reipl_set_type(enum ipl_type type) ...@@ -568,13 +578,15 @@ static int reipl_set_type(enum ipl_type type)
return 0; return 0;
} }
static ssize_t reipl_type_show(struct kset *kset, char *page) static ssize_t reipl_type_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
{ {
return sprintf(page, "%s\n", ipl_type_str(reipl_type)); return sprintf(page, "%s\n", ipl_type_str(reipl_type));
} }
static ssize_t reipl_type_store(struct kset *kset, const char *buf, static ssize_t reipl_type_store(struct kobject *kobj,
size_t len) struct kobj_attribute *attr,
const char *buf, size_t len)
{ {
int rc = -EINVAL; int rc = -EINVAL;
...@@ -587,10 +599,10 @@ static ssize_t reipl_type_store(struct kset *kset, const char *buf, ...@@ -587,10 +599,10 @@ static ssize_t reipl_type_store(struct kset *kset, const char *buf,
return (rc != 0) ? rc : len; return (rc != 0) ? rc : len;
} }
static struct subsys_attribute reipl_type_attr = static struct kobj_attribute reipl_type_attr =
__ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store); __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
static decl_subsys(reipl, NULL, NULL); static struct kset *reipl_kset;
/* /*
* dump section * dump section
...@@ -663,13 +675,15 @@ static int dump_set_type(enum dump_type type) ...@@ -663,13 +675,15 @@ static int dump_set_type(enum dump_type type)
return 0; return 0;
} }
static ssize_t dump_type_show(struct kset *kset, char *page) static ssize_t dump_type_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
{ {
return sprintf(page, "%s\n", dump_type_str(dump_type)); return sprintf(page, "%s\n", dump_type_str(dump_type));
} }
static ssize_t dump_type_store(struct kset *kset, const char *buf, static ssize_t dump_type_store(struct kobject *kobj,
size_t len) struct kobj_attribute *attr,
const char *buf, size_t len)
{ {
int rc = -EINVAL; int rc = -EINVAL;
...@@ -682,26 +696,28 @@ static ssize_t dump_type_store(struct kset *kset, const char *buf, ...@@ -682,26 +696,28 @@ static ssize_t dump_type_store(struct kset *kset, const char *buf,
return (rc != 0) ? rc : len; return (rc != 0) ? rc : len;
} }
static struct subsys_attribute dump_type_attr = static struct kobj_attribute dump_type_attr =
__ATTR(dump_type, 0644, dump_type_show, dump_type_store); __ATTR(dump_type, 0644, dump_type_show, dump_type_store);
static decl_subsys(dump, NULL, NULL); static struct kset *dump_kset;
/* /*
* Shutdown actions section * Shutdown actions section
*/ */
static decl_subsys(shutdown_actions, NULL, NULL); static struct kset *shutdown_actions_kset;
/* on panic */ /* on panic */
static ssize_t on_panic_show(struct kset *kset, char *page) static ssize_t on_panic_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
{ {
return sprintf(page, "%s\n", shutdown_action_str(on_panic_action)); return sprintf(page, "%s\n", shutdown_action_str(on_panic_action));
} }
static ssize_t on_panic_store(struct kset *kset, const char *buf, static ssize_t on_panic_store(struct kobject *kobj,
size_t len) struct kobj_attribute *attr,
const char *buf, size_t len)
{ {
if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0) if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0)
on_panic_action = SHUTDOWN_REIPL; on_panic_action = SHUTDOWN_REIPL;
...@@ -717,7 +733,7 @@ static ssize_t on_panic_store(struct kset *kset, const char *buf, ...@@ -717,7 +733,7 @@ static ssize_t on_panic_store(struct kset *kset, const char *buf,
return len; return len;
} }
static struct subsys_attribute on_panic_attr = static struct kobj_attribute on_panic_attr =
__ATTR(on_panic, 0644, on_panic_show, on_panic_store); __ATTR(on_panic, 0644, on_panic_show, on_panic_store);
void do_reipl(void) void do_reipl(void)
...@@ -814,23 +830,23 @@ static int __init ipl_register_fcp_files(void) ...@@ -814,23 +830,23 @@ static int __init ipl_register_fcp_files(void)
{ {
int rc; int rc;
rc = sysfs_create_group(&ipl_subsys.kobj, rc = sysfs_create_group(&ipl_kset->kobj,
&ipl_fcp_attr_group); &ipl_fcp_attr_group);
if (rc) if (rc)
goto out; goto out;
rc = sysfs_create_bin_file(&ipl_subsys.kobj, rc = sysfs_create_bin_file(&ipl_kset->kobj,
&ipl_parameter_attr); &ipl_parameter_attr);
if (rc) if (rc)
goto out_ipl_parm; goto out_ipl_parm;
rc = sysfs_create_bin_file(&ipl_subsys.kobj, rc = sysfs_create_bin_file(&ipl_kset->kobj,
&ipl_scp_data_attr); &ipl_scp_data_attr);
if (!rc) if (!rc)
goto out; goto out;
sysfs_remove_bin_file(&ipl_subsys.kobj, &ipl_parameter_attr); sysfs_remove_bin_file(&ipl_kset->kobj, &ipl_parameter_attr);
out_ipl_parm: out_ipl_parm:
sysfs_remove_group(&ipl_subsys.kobj, &ipl_fcp_attr_group); sysfs_remove_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
out: out:
return rc; return rc;
} }
...@@ -839,12 +855,12 @@ static int __init ipl_init(void) ...@@ -839,12 +855,12 @@ static int __init ipl_init(void)
{ {
int rc; int rc;
rc = firmware_register(&ipl_subsys); ipl_kset = kset_create_and_add("ipl", NULL, firmware_kobj);
if (rc) if (!ipl_kset)
return rc; return -ENOMEM;
switch (ipl_info.type) { switch (ipl_info.type) {
case IPL_TYPE_CCW: case IPL_TYPE_CCW:
rc = sysfs_create_group(&ipl_subsys.kobj, rc = sysfs_create_group(&ipl_kset->kobj,
&ipl_ccw_attr_group); &ipl_ccw_attr_group);
break; break;
case IPL_TYPE_FCP: case IPL_TYPE_FCP:
...@@ -852,16 +868,16 @@ static int __init ipl_init(void) ...@@ -852,16 +868,16 @@ static int __init ipl_init(void)
rc = ipl_register_fcp_files(); rc = ipl_register_fcp_files();
break; break;
case IPL_TYPE_NSS: case IPL_TYPE_NSS:
rc = sysfs_create_group(&ipl_subsys.kobj, rc = sysfs_create_group(&ipl_kset->kobj,
&ipl_nss_attr_group); &ipl_nss_attr_group);
break; break;
default: default:
rc = sysfs_create_group(&ipl_subsys.kobj, rc = sysfs_create_group(&ipl_kset->kobj,
&ipl_unknown_attr_group); &ipl_unknown_attr_group);
break; break;
} }
if (rc) if (rc)
firmware_unregister(&ipl_subsys); kset_unregister(ipl_kset);
return rc; return rc;
} }
...@@ -883,7 +899,7 @@ static int __init reipl_nss_init(void) ...@@ -883,7 +899,7 @@ static int __init reipl_nss_init(void)
if (!MACHINE_IS_VM) if (!MACHINE_IS_VM)
return 0; return 0;
rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_nss_attr_group); rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group);
if (rc) if (rc)
return rc; return rc;
strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1); strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
...@@ -898,7 +914,7 @@ static int __init reipl_ccw_init(void) ...@@ -898,7 +914,7 @@ static int __init reipl_ccw_init(void)
reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL); reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
if (!reipl_block_ccw) if (!reipl_block_ccw)
return -ENOMEM; return -ENOMEM;
rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_ccw_attr_group); rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group);
if (rc) { if (rc) {
free_page((unsigned long)reipl_block_ccw); free_page((unsigned long)reipl_block_ccw);
return rc; return rc;
...@@ -936,7 +952,7 @@ static int __init reipl_fcp_init(void) ...@@ -936,7 +952,7 @@ static int __init reipl_fcp_init(void)
reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
if (!reipl_block_fcp) if (!reipl_block_fcp)
return -ENOMEM; return -ENOMEM;
rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_fcp_attr_group); rc = sysfs_create_group(&reipl_kset->kobj, &reipl_fcp_attr_group);
if (rc) { if (rc) {
free_page((unsigned long)reipl_block_fcp); free_page((unsigned long)reipl_block_fcp);
return rc; return rc;
...@@ -958,12 +974,12 @@ static int __init reipl_init(void) ...@@ -958,12 +974,12 @@ static int __init reipl_init(void)
{ {
int rc; int rc;
rc = firmware_register(&reipl_subsys); reipl_kset = kset_create_and_add("reipl", NULL, firmware_kobj);
if (rc) if (!reipl_kset)
return rc; return -ENOMEM;
rc = subsys_create_file(&reipl_subsys, &reipl_type_attr); rc = sysfs_create_file(&reipl_kset->kobj, &reipl_type_attr.attr);
if (rc) { if (rc) {
firmware_unregister(&reipl_subsys); kset_unregister(reipl_kset);
return rc; return rc;
} }
rc = reipl_ccw_init(); rc = reipl_ccw_init();
...@@ -988,7 +1004,7 @@ static int __init dump_ccw_init(void) ...@@ -988,7 +1004,7 @@ static int __init dump_ccw_init(void)
dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL); dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
if (!dump_block_ccw) if (!dump_block_ccw)
return -ENOMEM; return -ENOMEM;
rc = sysfs_create_group(&dump_subsys.kobj, &dump_ccw_attr_group); rc = sysfs_create_group(&dump_kset->kobj, &dump_ccw_attr_group);
if (rc) { if (rc) {
free_page((unsigned long)dump_block_ccw); free_page((unsigned long)dump_block_ccw);
return rc; return rc;
...@@ -1012,7 +1028,7 @@ static int __init dump_fcp_init(void) ...@@ -1012,7 +1028,7 @@ static int __init dump_fcp_init(void)
dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
if (!dump_block_fcp) if (!dump_block_fcp)
return -ENOMEM; return -ENOMEM;
rc = sysfs_create_group(&dump_subsys.kobj, &dump_fcp_attr_group); rc = sysfs_create_group(&dump_kset->kobj, &dump_fcp_attr_group);
if (rc) { if (rc) {
free_page((unsigned long)dump_block_fcp); free_page((unsigned long)dump_block_fcp);
return rc; return rc;
...@@ -1047,12 +1063,12 @@ static int __init dump_init(void) ...@@ -1047,12 +1063,12 @@ static int __init dump_init(void)
{ {
int rc; int rc;
rc = firmware_register(&dump_subsys); dump_kset = kset_create_and_add("dump", NULL, firmware_kobj);
if (rc) if (!dump_kset)
return rc; return -ENOMEM;
rc = subsys_create_file(&dump_subsys, &dump_type_attr); rc = sysfs_create_file(&dump_kset->kobj, &dump_type_attr);
if (rc) { if (rc) {
firmware_unregister(&dump_subsys); kset_unregister(dump_kset);
return rc; return rc;
} }
rc = dump_ccw_init(); rc = dump_ccw_init();
...@@ -1069,12 +1085,13 @@ static int __init shutdown_actions_init(void) ...@@ -1069,12 +1085,13 @@ static int __init shutdown_actions_init(void)
{ {
int rc; int rc;
rc = firmware_register(&shutdown_actions_subsys); shutdown_actions_kset = kset_create_and_add("shutdown_actions", NULL,
if (rc) firmware_kobj);
return rc; if (!shutdown_actions_kset)
rc = subsys_create_file(&shutdown_actions_subsys, &on_panic_attr); return -ENOMEM;
rc = sysfs_create_file(&shutdown_actions_kset->kobj, &on_panic_attr);
if (rc) { if (rc) {
firmware_unregister(&shutdown_actions_subsys); kset_unregister(shutdown_actions_kset);
return rc; return rc;
} }
atomic_notifier_chain_register(&panic_notifier_list, atomic_notifier_chain_register(&panic_notifier_list,
......
...@@ -1145,7 +1145,7 @@ static void etr_work_fn(struct work_struct *work) ...@@ -1145,7 +1145,7 @@ static void etr_work_fn(struct work_struct *work)
* Sysfs interface functions * Sysfs interface functions
*/ */
static struct sysdev_class etr_sysclass = { static struct sysdev_class etr_sysclass = {
set_kset_name("etr") .name = "etr",
}; };
static struct sys_device etr_port0_dev = { static struct sys_device etr_port0_dev = {
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include <asm/dma.h> #include <asm/dma.h>
static struct sysdev_class dma_sysclass = { static struct sysdev_class dma_sysclass = {
set_kset_name("dma"), .name = "dma",
}; };
EXPORT_SYMBOL(dma_sysclass); EXPORT_SYMBOL(dma_sysclass);
......
...@@ -341,17 +341,18 @@ static int __devinit sq_sysdev_add(struct sys_device *sysdev) ...@@ -341,17 +341,18 @@ static int __devinit sq_sysdev_add(struct sys_device *sysdev)
{ {
unsigned int cpu = sysdev->id; unsigned int cpu = sysdev->id;
struct kobject *kobj; struct kobject *kobj;
int error;
sq_kobject[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL); sq_kobject[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL);
if (unlikely(!sq_kobject[cpu])) if (unlikely(!sq_kobject[cpu]))
return -ENOMEM; return -ENOMEM;
kobj = sq_kobject[cpu]; kobj = sq_kobject[cpu];
kobj->parent = &sysdev->kobj; error = kobject_init_and_add(kobj, &ktype_percpu_entry, &sysdev->kobj,
kobject_set_name(kobj, "%s", "sq"); "%s", "sq");
kobj->ktype = &ktype_percpu_entry; if (!error)
kobject_uevent(kobj, KOBJ_ADD);
return kobject_register(kobj); return error;
} }
static int __devexit sq_sysdev_remove(struct sys_device *sysdev) static int __devexit sq_sysdev_remove(struct sys_device *sysdev)
...@@ -359,7 +360,7 @@ static int __devexit sq_sysdev_remove(struct sys_device *sysdev) ...@@ -359,7 +360,7 @@ static int __devexit sq_sysdev_remove(struct sys_device *sysdev)
unsigned int cpu = sysdev->id; unsigned int cpu = sysdev->id;
struct kobject *kobj = sq_kobject[cpu]; struct kobject *kobj = sq_kobject[cpu];
kobject_unregister(kobj); kobject_put(kobj);
return 0; return 0;
} }
......
...@@ -174,7 +174,7 @@ int timer_resume(struct sys_device *dev) ...@@ -174,7 +174,7 @@ int timer_resume(struct sys_device *dev)
#endif #endif
static struct sysdev_class timer_sysclass = { static struct sysdev_class timer_sysclass = {
set_kset_name("timer"), .name = "timer",
.suspend = timer_suspend, .suspend = timer_suspend,
.resume = timer_resume, .resume = timer_resume,
}; };
......
...@@ -1530,7 +1530,7 @@ static int lapic_resume(struct sys_device *dev) ...@@ -1530,7 +1530,7 @@ static int lapic_resume(struct sys_device *dev)
*/ */
static struct sysdev_class lapic_sysclass = { static struct sysdev_class lapic_sysclass = {
set_kset_name("lapic"), .name = "lapic",
.resume = lapic_resume, .resume = lapic_resume,
.suspend = lapic_suspend, .suspend = lapic_suspend,
}; };
......
...@@ -639,7 +639,7 @@ static int lapic_resume(struct sys_device *dev) ...@@ -639,7 +639,7 @@ static int lapic_resume(struct sys_device *dev)
} }
static struct sysdev_class lapic_sysclass = { static struct sysdev_class lapic_sysclass = {
set_kset_name("lapic"), .name = "lapic",
.resume = lapic_resume, .resume = lapic_resume,
.suspend = lapic_suspend, .suspend = lapic_suspend,
}; };
......
...@@ -733,10 +733,8 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) ...@@ -733,10 +733,8 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
if (unlikely(retval < 0)) if (unlikely(retval < 0))
return retval; return retval;
cache_kobject[cpu]->parent = &sys_dev->kobj; retval = kobject_init_and_add(cache_kobject[cpu], &ktype_percpu_entry,
kobject_set_name(cache_kobject[cpu], "%s", "cache"); &sys_dev->kobj, "%s", "cache");
cache_kobject[cpu]->ktype = &ktype_percpu_entry;
retval = kobject_register(cache_kobject[cpu]);
if (retval < 0) { if (retval < 0) {
cpuid4_cache_sysfs_exit(cpu); cpuid4_cache_sysfs_exit(cpu);
return retval; return retval;
...@@ -746,23 +744,23 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) ...@@ -746,23 +744,23 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
this_object = INDEX_KOBJECT_PTR(cpu,i); this_object = INDEX_KOBJECT_PTR(cpu,i);
this_object->cpu = cpu; this_object->cpu = cpu;
this_object->index = i; this_object->index = i;
this_object->kobj.parent = cache_kobject[cpu]; retval = kobject_init_and_add(&(this_object->kobj),
kobject_set_name(&(this_object->kobj), "index%1lu", i); &ktype_cache, cache_kobject[cpu],
this_object->kobj.ktype = &ktype_cache; "index%1lu", i);
retval = kobject_register(&(this_object->kobj));
if (unlikely(retval)) { if (unlikely(retval)) {
for (j = 0; j < i; j++) { for (j = 0; j < i; j++) {
kobject_unregister( kobject_put(&(INDEX_KOBJECT_PTR(cpu,j)->kobj));
&(INDEX_KOBJECT_PTR(cpu,j)->kobj));
} }
kobject_unregister(cache_kobject[cpu]); kobject_put(cache_kobject[cpu]);
cpuid4_cache_sysfs_exit(cpu); cpuid4_cache_sysfs_exit(cpu);
break; break;
} }
kobject_uevent(&(this_object->kobj), KOBJ_ADD);
} }
if (!retval) if (!retval)
cpu_set(cpu, cache_dev_map); cpu_set(cpu, cache_dev_map);
kobject_uevent(cache_kobject[cpu], KOBJ_ADD);
return retval; return retval;
} }
...@@ -778,8 +776,8 @@ static void __cpuinit cache_remove_dev(struct sys_device * sys_dev) ...@@ -778,8 +776,8 @@ static void __cpuinit cache_remove_dev(struct sys_device * sys_dev)
cpu_clear(cpu, cache_dev_map); cpu_clear(cpu, cache_dev_map);
for (i = 0; i < num_cache_leaves; i++) for (i = 0; i < num_cache_leaves; i++)
kobject_unregister(&(INDEX_KOBJECT_PTR(cpu,i)->kobj)); kobject_put(&(INDEX_KOBJECT_PTR(cpu,i)->kobj));
kobject_unregister(cache_kobject[cpu]); kobject_put(cache_kobject[cpu]);
cpuid4_cache_sysfs_exit(cpu); cpuid4_cache_sysfs_exit(cpu);
} }
......
...@@ -745,7 +745,7 @@ static void mce_restart(void) ...@@ -745,7 +745,7 @@ static void mce_restart(void)
static struct sysdev_class mce_sysclass = { static struct sysdev_class mce_sysclass = {
.resume = mce_resume, .resume = mce_resume,
set_kset_name("machinecheck"), .name = "machinecheck",
}; };
DEFINE_PER_CPU(struct sys_device, device_mce); DEFINE_PER_CPU(struct sys_device, device_mce);
......
...@@ -65,7 +65,7 @@ static struct threshold_block threshold_defaults = { ...@@ -65,7 +65,7 @@ static struct threshold_block threshold_defaults = {
}; };
struct threshold_bank { struct threshold_bank {
struct kobject kobj; struct kobject *kobj;
struct threshold_block *blocks; struct threshold_block *blocks;
cpumask_t cpus; cpumask_t cpus;
}; };
...@@ -432,10 +432,9 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu, ...@@ -432,10 +432,9 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
else else
per_cpu(threshold_banks, cpu)[bank]->blocks = b; per_cpu(threshold_banks, cpu)[bank]->blocks = b;
kobject_set_name(&b->kobj, "misc%i", block); err = kobject_init_and_add(&b->kobj, &threshold_ktype,
b->kobj.parent = &per_cpu(threshold_banks, cpu)[bank]->kobj; per_cpu(threshold_banks, cpu)[bank]->kobj,
b->kobj.ktype = &threshold_ktype; "misc%i", block);
err = kobject_register(&b->kobj);
if (err) if (err)
goto out_free; goto out_free;
recurse: recurse:
...@@ -451,11 +450,13 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu, ...@@ -451,11 +450,13 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
if (err) if (err)
goto out_free; goto out_free;
kobject_uevent(&b->kobj, KOBJ_ADD);
return err; return err;
out_free: out_free:
if (b) { if (b) {
kobject_unregister(&b->kobj); kobject_put(&b->kobj);
kfree(b); kfree(b);
} }
return err; return err;
...@@ -489,7 +490,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) ...@@ -489,7 +490,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
goto out; goto out;
err = sysfs_create_link(&per_cpu(device_mce, cpu).kobj, err = sysfs_create_link(&per_cpu(device_mce, cpu).kobj,
&b->kobj, name); b->kobj, name);
if (err) if (err)
goto out; goto out;
...@@ -505,16 +506,15 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) ...@@ -505,16 +506,15 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
goto out; goto out;
} }
kobject_set_name(&b->kobj, "threshold_bank%i", bank); b->kobj = kobject_create_and_add(name, &per_cpu(device_mce, cpu).kobj);
b->kobj.parent = &per_cpu(device_mce, cpu).kobj; if (!b->kobj)
goto out_free;
#ifndef CONFIG_SMP #ifndef CONFIG_SMP
b->cpus = CPU_MASK_ALL; b->cpus = CPU_MASK_ALL;
#else #else
b->cpus = per_cpu(cpu_core_map, cpu); b->cpus = per_cpu(cpu_core_map, cpu);
#endif #endif
err = kobject_register(&b->kobj);
if (err)
goto out_free;
per_cpu(threshold_banks, cpu)[bank] = b; per_cpu(threshold_banks, cpu)[bank] = b;
...@@ -531,7 +531,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) ...@@ -531,7 +531,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
continue; continue;
err = sysfs_create_link(&per_cpu(device_mce, i).kobj, err = sysfs_create_link(&per_cpu(device_mce, i).kobj,
&b->kobj, name); b->kobj, name);
if (err) if (err)
goto out; goto out;
...@@ -581,7 +581,7 @@ static void deallocate_threshold_block(unsigned int cpu, ...@@ -581,7 +581,7 @@ static void deallocate_threshold_block(unsigned int cpu,
return; return;
list_for_each_entry_safe(pos, tmp, &head->blocks->miscj, miscj) { list_for_each_entry_safe(pos, tmp, &head->blocks->miscj, miscj) {
kobject_unregister(&pos->kobj); kobject_put(&pos->kobj);
list_del(&pos->miscj); list_del(&pos->miscj);
kfree(pos); kfree(pos);
} }
...@@ -627,7 +627,7 @@ static void threshold_remove_bank(unsigned int cpu, int bank) ...@@ -627,7 +627,7 @@ static void threshold_remove_bank(unsigned int cpu, int bank)
deallocate_threshold_block(cpu, bank); deallocate_threshold_block(cpu, bank);
free_out: free_out:
kobject_unregister(&b->kobj); kobject_put(b->kobj);
kfree(b); kfree(b);
per_cpu(threshold_banks, cpu)[bank] = NULL; per_cpu(threshold_banks, cpu)[bank] = NULL;
} }
......
...@@ -157,15 +157,15 @@ static int __cpuinit cpuid_class_cpu_callback(struct notifier_block *nfb, ...@@ -157,15 +157,15 @@ static int __cpuinit cpuid_class_cpu_callback(struct notifier_block *nfb,
switch (action) { switch (action) {
case CPU_UP_PREPARE: case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
err = cpuid_device_create(cpu); err = cpuid_device_create(cpu);
break; break;
case CPU_UP_CANCELED: case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD: case CPU_DEAD:
case CPU_DEAD_FROZEN:
cpuid_device_destroy(cpu); cpuid_device_destroy(cpu);
break; break;
case CPU_UP_CANCELED_FROZEN:
destroy_suspended_device(cpuid_class, MKDEV(CPUID_MAJOR, cpu));
break;
} }
return err ? NOTIFY_BAD : NOTIFY_OK; return err ? NOTIFY_BAD : NOTIFY_OK;
} }
......
...@@ -51,7 +51,7 @@ static int i8237A_suspend(struct sys_device *dev, pm_message_t state) ...@@ -51,7 +51,7 @@ static int i8237A_suspend(struct sys_device *dev, pm_message_t state)
} }
static struct sysdev_class i8237_sysdev_class = { static struct sysdev_class i8237_sysdev_class = {
set_kset_name("i8237"), .name = "i8237",
.suspend = i8237A_suspend, .suspend = i8237A_suspend,
.resume = i8237A_resume, .resume = i8237A_resume,
}; };
......
...@@ -258,7 +258,7 @@ static int i8259A_shutdown(struct sys_device *dev) ...@@ -258,7 +258,7 @@ static int i8259A_shutdown(struct sys_device *dev)
} }
static struct sysdev_class i8259_sysdev_class = { static struct sysdev_class i8259_sysdev_class = {
set_kset_name("i8259"), .name = "i8259",
.suspend = i8259A_suspend, .suspend = i8259A_suspend,
.resume = i8259A_resume, .resume = i8259A_resume,
.shutdown = i8259A_shutdown, .shutdown = i8259A_shutdown,
......
...@@ -370,7 +370,7 @@ static int i8259A_shutdown(struct sys_device *dev) ...@@ -370,7 +370,7 @@ static int i8259A_shutdown(struct sys_device *dev)
} }
static struct sysdev_class i8259_sysdev_class = { static struct sysdev_class i8259_sysdev_class = {
set_kset_name("i8259"), .name = "i8259",
.suspend = i8259A_suspend, .suspend = i8259A_suspend,
.resume = i8259A_resume, .resume = i8259A_resume,
.shutdown = i8259A_shutdown, .shutdown = i8259A_shutdown,
......
...@@ -2401,7 +2401,7 @@ static int ioapic_resume(struct sys_device *dev) ...@@ -2401,7 +2401,7 @@ static int ioapic_resume(struct sys_device *dev)
} }
static struct sysdev_class ioapic_sysdev_class = { static struct sysdev_class ioapic_sysdev_class = {
set_kset_name("ioapic"), .name = "ioapic",
.suspend = ioapic_suspend, .suspend = ioapic_suspend,
.resume = ioapic_resume, .resume = ioapic_resume,
}; };
......
...@@ -1850,7 +1850,7 @@ static int ioapic_resume(struct sys_device *dev) ...@@ -1850,7 +1850,7 @@ static int ioapic_resume(struct sys_device *dev)
} }
static struct sysdev_class ioapic_sysdev_class = { static struct sysdev_class ioapic_sysdev_class = {
set_kset_name("ioapic"), .name = "ioapic",
.suspend = ioapic_suspend, .suspend = ioapic_suspend,
.resume = ioapic_resume, .resume = ioapic_resume,
}; };
......
...@@ -155,15 +155,15 @@ static int __cpuinit msr_class_cpu_callback(struct notifier_block *nfb, ...@@ -155,15 +155,15 @@ static int __cpuinit msr_class_cpu_callback(struct notifier_block *nfb,
switch (action) { switch (action) {
case CPU_UP_PREPARE: case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
err = msr_device_create(cpu); err = msr_device_create(cpu);
break; break;
case CPU_UP_CANCELED: case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD: case CPU_DEAD:
case CPU_DEAD_FROZEN:
msr_device_destroy(cpu); msr_device_destroy(cpu);
break; break;
case CPU_UP_CANCELED_FROZEN:
destroy_suspended_device(msr_class, MKDEV(MSR_MAJOR, cpu));
break;
} }
return err ? NOTIFY_BAD : NOTIFY_OK; return err ? NOTIFY_BAD : NOTIFY_OK;
} }
......
...@@ -176,7 +176,7 @@ static int lapic_nmi_resume(struct sys_device *dev) ...@@ -176,7 +176,7 @@ static int lapic_nmi_resume(struct sys_device *dev)
static struct sysdev_class nmi_sysclass = { static struct sysdev_class nmi_sysclass = {
set_kset_name("lapic_nmi"), .name = "lapic_nmi",
.resume = lapic_nmi_resume, .resume = lapic_nmi_resume,
.suspend = lapic_nmi_suspend, .suspend = lapic_nmi_suspend,
}; };
......
...@@ -211,7 +211,7 @@ static int lapic_nmi_resume(struct sys_device *dev) ...@@ -211,7 +211,7 @@ static int lapic_nmi_resume(struct sys_device *dev)
} }
static struct sysdev_class nmi_sysclass = { static struct sysdev_class nmi_sysclass = {
set_kset_name("lapic_nmi"), .name = "lapic_nmi",
.resume = lapic_nmi_resume, .resume = lapic_nmi_resume,
.suspend = lapic_nmi_suspend, .suspend = lapic_nmi_suspend,
}; };
......
...@@ -51,7 +51,7 @@ static int nmi_resume(struct sys_device *dev) ...@@ -51,7 +51,7 @@ static int nmi_resume(struct sys_device *dev)
static struct sysdev_class oprofile_sysclass = { static struct sysdev_class oprofile_sysclass = {
set_kset_name("oprofile"), .name = "oprofile",
.resume = nmi_resume, .resume = nmi_resume,
.suspend = nmi_suspend, .suspend = nmi_suspend,
}; };
......
...@@ -185,9 +185,7 @@ static elevator_t *elevator_alloc(struct request_queue *q, ...@@ -185,9 +185,7 @@ static elevator_t *elevator_alloc(struct request_queue *q,
eq->ops = &e->ops; eq->ops = &e->ops;
eq->elevator_type = e; eq->elevator_type = e;
kobject_init(&eq->kobj); kobject_init(&eq->kobj, &elv_ktype);
kobject_set_name(&eq->kobj, "%s", "iosched");
eq->kobj.ktype = &elv_ktype;
mutex_init(&eq->sysfs_lock); mutex_init(&eq->sysfs_lock);
eq->hash = kmalloc_node(sizeof(struct hlist_head) * ELV_HASH_ENTRIES, eq->hash = kmalloc_node(sizeof(struct hlist_head) * ELV_HASH_ENTRIES,
...@@ -931,9 +929,7 @@ int elv_register_queue(struct request_queue *q) ...@@ -931,9 +929,7 @@ int elv_register_queue(struct request_queue *q)
elevator_t *e = q->elevator; elevator_t *e = q->elevator;
int error; int error;
e->kobj.parent = &q->kobj; error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched");
error = kobject_add(&e->kobj);
if (!error) { if (!error) {
struct elv_fs_entry *attr = e->elevator_type->elevator_attrs; struct elv_fs_entry *attr = e->elevator_type->elevator_attrs;
if (attr) { if (attr) {
......
...@@ -17,8 +17,10 @@ ...@@ -17,8 +17,10 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/mutex.h> #include <linux/mutex.h>
struct kset block_subsys; static DEFINE_MUTEX(block_class_lock);
static DEFINE_MUTEX(block_subsys_lock); #ifndef CONFIG_SYSFS_DEPRECATED
struct kobject *block_depr;
#endif
/* /*
* Can be deleted altogether. Later. * Can be deleted altogether. Later.
...@@ -37,19 +39,17 @@ static inline int major_to_index(int major) ...@@ -37,19 +39,17 @@ static inline int major_to_index(int major)
} }
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
void blkdev_show(struct seq_file *f, off_t offset) void blkdev_show(struct seq_file *f, off_t offset)
{ {
struct blk_major_name *dp; struct blk_major_name *dp;
if (offset < BLKDEV_MAJOR_HASH_SIZE) { if (offset < BLKDEV_MAJOR_HASH_SIZE) {
mutex_lock(&block_subsys_lock); mutex_lock(&block_class_lock);
for (dp = major_names[offset]; dp; dp = dp->next) for (dp = major_names[offset]; dp; dp = dp->next)
seq_printf(f, "%3d %s\n", dp->major, dp->name); seq_printf(f, "%3d %s\n", dp->major, dp->name);
mutex_unlock(&block_subsys_lock); mutex_unlock(&block_class_lock);
} }
} }
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
int register_blkdev(unsigned int major, const char *name) int register_blkdev(unsigned int major, const char *name)
...@@ -57,7 +57,7 @@ int register_blkdev(unsigned int major, const char *name) ...@@ -57,7 +57,7 @@ int register_blkdev(unsigned int major, const char *name)
struct blk_major_name **n, *p; struct blk_major_name **n, *p;
int index, ret = 0; int index, ret = 0;
mutex_lock(&block_subsys_lock); mutex_lock(&block_class_lock);
/* temporary */ /* temporary */
if (major == 0) { if (major == 0) {
...@@ -102,7 +102,7 @@ int register_blkdev(unsigned int major, const char *name) ...@@ -102,7 +102,7 @@ int register_blkdev(unsigned int major, const char *name)
kfree(p); kfree(p);
} }
out: out:
mutex_unlock(&block_subsys_lock); mutex_unlock(&block_class_lock);
return ret; return ret;
} }
...@@ -114,7 +114,7 @@ void unregister_blkdev(unsigned int major, const char *name) ...@@ -114,7 +114,7 @@ void unregister_blkdev(unsigned int major, const char *name)
struct blk_major_name *p = NULL; struct blk_major_name *p = NULL;
int index = major_to_index(major); int index = major_to_index(major);
mutex_lock(&block_subsys_lock); mutex_lock(&block_class_lock);
for (n = &major_names[index]; *n; n = &(*n)->next) for (n = &major_names[index]; *n; n = &(*n)->next)
if ((*n)->major == major) if ((*n)->major == major)
break; break;
...@@ -124,7 +124,7 @@ void unregister_blkdev(unsigned int major, const char *name) ...@@ -124,7 +124,7 @@ void unregister_blkdev(unsigned int major, const char *name)
p = *n; p = *n;
*n = p->next; *n = p->next;
} }
mutex_unlock(&block_subsys_lock); mutex_unlock(&block_class_lock);
kfree(p); kfree(p);
} }
...@@ -137,29 +137,30 @@ static struct kobj_map *bdev_map; ...@@ -137,29 +137,30 @@ static struct kobj_map *bdev_map;
* range must be nonzero * range must be nonzero
* The hash chain is sorted on range, so that subranges can override. * The hash chain is sorted on range, so that subranges can override.
*/ */
void blk_register_region(dev_t dev, unsigned long range, struct module *module, void blk_register_region(dev_t devt, unsigned long range, struct module *module,
struct kobject *(*probe)(dev_t, int *, void *), struct kobject *(*probe)(dev_t, int *, void *),
int (*lock)(dev_t, void *), void *data) int (*lock)(dev_t, void *), void *data)
{ {
kobj_map(bdev_map, dev, range, module, probe, lock, data); kobj_map(bdev_map, devt, range, module, probe, lock, data);
} }
EXPORT_SYMBOL(blk_register_region); EXPORT_SYMBOL(blk_register_region);
void blk_unregister_region(dev_t dev, unsigned long range) void blk_unregister_region(dev_t devt, unsigned long range)
{ {
kobj_unmap(bdev_map, dev, range); kobj_unmap(bdev_map, devt, range);
} }
EXPORT_SYMBOL(blk_unregister_region); EXPORT_SYMBOL(blk_unregister_region);
static struct kobject *exact_match(dev_t dev, int *part, void *data) static struct kobject *exact_match(dev_t devt, int *part, void *data)
{ {
struct gendisk *p = data; struct gendisk *p = data;
return &p->kobj;
return &p->dev.kobj;
} }
static int exact_lock(dev_t dev, void *data) static int exact_lock(dev_t devt, void *data)
{ {
struct gendisk *p = data; struct gendisk *p = data;
...@@ -194,8 +195,6 @@ void unlink_gendisk(struct gendisk *disk) ...@@ -194,8 +195,6 @@ void unlink_gendisk(struct gendisk *disk)
disk->minors); disk->minors);
} }
#define to_disk(obj) container_of(obj,struct gendisk,kobj)
/** /**
* get_gendisk - get partitioning information for a given device * get_gendisk - get partitioning information for a given device
* @dev: device to get partitioning information for * @dev: device to get partitioning information for
...@@ -203,10 +202,12 @@ void unlink_gendisk(struct gendisk *disk) ...@@ -203,10 +202,12 @@ void unlink_gendisk(struct gendisk *disk)
* This function gets the structure containing partitioning * This function gets the structure containing partitioning
* information for the given device @dev. * information for the given device @dev.
*/ */
struct gendisk *get_gendisk(dev_t dev, int *part) struct gendisk *get_gendisk(dev_t devt, int *part)
{ {
struct kobject *kobj = kobj_lookup(bdev_map, dev, part); struct kobject *kobj = kobj_lookup(bdev_map, devt, part);
return kobj ? to_disk(kobj) : NULL; struct device *dev = kobj_to_dev(kobj);
return kobj ? dev_to_disk(dev) : NULL;
} }
/* /*
...@@ -216,13 +217,17 @@ struct gendisk *get_gendisk(dev_t dev, int *part) ...@@ -216,13 +217,17 @@ struct gendisk *get_gendisk(dev_t dev, int *part)
*/ */
void __init printk_all_partitions(void) void __init printk_all_partitions(void)
{ {
int n; struct device *dev;
struct gendisk *sgp; struct gendisk *sgp;
char buf[BDEVNAME_SIZE];
int n;
mutex_lock(&block_subsys_lock); mutex_lock(&block_class_lock);
/* For each block device... */ /* For each block device... */
list_for_each_entry(sgp, &block_subsys.list, kobj.entry) { list_for_each_entry(dev, &block_class.devices, node) {
char buf[BDEVNAME_SIZE]; if (dev->type != &disk_type)
continue;
sgp = dev_to_disk(dev);
/* /*
* Don't show empty devices or things that have been surpressed * Don't show empty devices or things that have been surpressed
*/ */
...@@ -255,38 +260,46 @@ void __init printk_all_partitions(void) ...@@ -255,38 +260,46 @@ void __init printk_all_partitions(void)
sgp->major, n + 1 + sgp->first_minor, sgp->major, n + 1 + sgp->first_minor,
(unsigned long long)sgp->part[n]->nr_sects >> 1, (unsigned long long)sgp->part[n]->nr_sects >> 1,
disk_name(sgp, n + 1, buf)); disk_name(sgp, n + 1, buf));
} /* partition subloop */ }
} /* Block device loop */ }
mutex_unlock(&block_subsys_lock); mutex_unlock(&block_class_lock);
return;
} }
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
/* iterator */ /* iterator */
static void *part_start(struct seq_file *part, loff_t *pos) static void *part_start(struct seq_file *part, loff_t *pos)
{ {
struct list_head *p; loff_t k = *pos;
loff_t l = *pos; struct device *dev;
mutex_lock(&block_subsys_lock); mutex_lock(&block_class_lock);
list_for_each(p, &block_subsys.list) list_for_each_entry(dev, &block_class.devices, node) {
if (!l--) if (dev->type != &disk_type)
return list_entry(p, struct gendisk, kobj.entry); continue;
if (!k--)
return dev_to_disk(dev);
}
return NULL; return NULL;
} }
static void *part_next(struct seq_file *part, void *v, loff_t *pos) static void *part_next(struct seq_file *part, void *v, loff_t *pos)
{ {
struct list_head *p = ((struct gendisk *)v)->kobj.entry.next; struct gendisk *gp = v;
struct device *dev;
++*pos; ++*pos;
return p==&block_subsys.list ? NULL : list_for_each_entry(dev, &gp->dev.node, node) {
list_entry(p, struct gendisk, kobj.entry); if (&dev->node == &block_class.devices)
return NULL;
if (dev->type == &disk_type)
return dev_to_disk(dev);
}
return NULL;
} }
static void part_stop(struct seq_file *part, void *v) static void part_stop(struct seq_file *part, void *v)
{ {
mutex_unlock(&block_subsys_lock); mutex_unlock(&block_class_lock);
} }
static int show_partition(struct seq_file *part, void *v) static int show_partition(struct seq_file *part, void *v)
...@@ -295,7 +308,7 @@ static int show_partition(struct seq_file *part, void *v) ...@@ -295,7 +308,7 @@ static int show_partition(struct seq_file *part, void *v)
int n; int n;
char buf[BDEVNAME_SIZE]; char buf[BDEVNAME_SIZE];
if (&sgp->kobj.entry == block_subsys.list.next) if (&sgp->dev.node == block_class.devices.next)
seq_puts(part, "major minor #blocks name\n\n"); seq_puts(part, "major minor #blocks name\n\n");
/* Don't show non-partitionable removeable devices or empty devices */ /* Don't show non-partitionable removeable devices or empty devices */
...@@ -325,110 +338,81 @@ static int show_partition(struct seq_file *part, void *v) ...@@ -325,110 +338,81 @@ static int show_partition(struct seq_file *part, void *v)
} }
struct seq_operations partitions_op = { struct seq_operations partitions_op = {
.start =part_start, .start = part_start,
.next = part_next, .next = part_next,
.stop = part_stop, .stop = part_stop,
.show = show_partition .show = show_partition
}; };
#endif #endif
extern int blk_dev_init(void); extern int blk_dev_init(void);
static struct kobject *base_probe(dev_t dev, int *part, void *data) static struct kobject *base_probe(dev_t devt, int *part, void *data)
{ {
if (request_module("block-major-%d-%d", MAJOR(dev), MINOR(dev)) > 0) if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0)
/* Make old-style 2.4 aliases work */ /* Make old-style 2.4 aliases work */
request_module("block-major-%d", MAJOR(dev)); request_module("block-major-%d", MAJOR(devt));
return NULL; return NULL;
} }
static int __init genhd_device_init(void) static int __init genhd_device_init(void)
{ {
int err; class_register(&block_class);
bdev_map = kobj_map_init(base_probe, &block_class_lock);
bdev_map = kobj_map_init(base_probe, &block_subsys_lock);
blk_dev_init(); blk_dev_init();
err = subsystem_register(&block_subsys);
if (err < 0) #ifndef CONFIG_SYSFS_DEPRECATED
printk(KERN_WARNING "%s: subsystem_register error: %d\n", /* create top-level block dir */
__FUNCTION__, err); block_depr = kobject_create_and_add("block", NULL);
return err; #endif
return 0;
} }
subsys_initcall(genhd_device_init); subsys_initcall(genhd_device_init);
static ssize_t disk_range_show(struct device *dev,
struct device_attribute *attr, char *buf)
/*
* kobject & sysfs bindings for block devices
*/
static ssize_t disk_attr_show(struct kobject *kobj, struct attribute *attr,
char *page)
{ {
struct gendisk *disk = to_disk(kobj); struct gendisk *disk = dev_to_disk(dev);
struct disk_attribute *disk_attr =
container_of(attr,struct disk_attribute,attr);
ssize_t ret = -EIO;
if (disk_attr->show) return sprintf(buf, "%d\n", disk->minors);
ret = disk_attr->show(disk,page);
return ret;
} }
static ssize_t disk_attr_store(struct kobject * kobj, struct attribute * attr, static ssize_t disk_removable_show(struct device *dev,
const char *page, size_t count) struct device_attribute *attr, char *buf)
{ {
struct gendisk *disk = to_disk(kobj); struct gendisk *disk = dev_to_disk(dev);
struct disk_attribute *disk_attr =
container_of(attr,struct disk_attribute,attr);
ssize_t ret = 0;
if (disk_attr->store) return sprintf(buf, "%d\n",
ret = disk_attr->store(disk, page, count); (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
return ret;
} }
static struct sysfs_ops disk_sysfs_ops = { static ssize_t disk_size_show(struct device *dev,
.show = &disk_attr_show, struct device_attribute *attr, char *buf)
.store = &disk_attr_store,
};
static ssize_t disk_uevent_store(struct gendisk * disk,
const char *buf, size_t count)
{
kobject_uevent(&disk->kobj, KOBJ_ADD);
return count;
}
static ssize_t disk_dev_read(struct gendisk * disk, char *page)
{
dev_t base = MKDEV(disk->major, disk->first_minor);
return print_dev_t(page, base);
}
static ssize_t disk_range_read(struct gendisk * disk, char *page)
{ {
return sprintf(page, "%d\n", disk->minors); struct gendisk *disk = dev_to_disk(dev);
}
static ssize_t disk_removable_read(struct gendisk * disk, char *page)
{
return sprintf(page, "%d\n",
(disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
return sprintf(buf, "%llu\n", (unsigned long long)get_capacity(disk));
} }
static ssize_t disk_size_read(struct gendisk * disk, char *page)
{ static ssize_t disk_capability_show(struct device *dev,
return sprintf(page, "%llu\n", (unsigned long long)get_capacity(disk)); struct device_attribute *attr, char *buf)
}
static ssize_t disk_capability_read(struct gendisk *disk, char *page)
{ {
return sprintf(page, "%x\n", disk->flags); struct gendisk *disk = dev_to_disk(dev);
return sprintf(buf, "%x\n", disk->flags);
} }
static ssize_t disk_stats_read(struct gendisk * disk, char *page)
static ssize_t disk_stat_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ {
struct gendisk *disk = dev_to_disk(dev);
preempt_disable(); preempt_disable();
disk_round_stats(disk); disk_round_stats(disk);
preempt_enable(); preempt_enable();
return sprintf(page, return sprintf(buf,
"%8lu %8lu %8llu %8u " "%8lu %8lu %8llu %8u "
"%8lu %8lu %8llu %8u " "%8lu %8lu %8llu %8u "
"%8u %8u %8u" "%8u %8u %8u"
...@@ -445,40 +429,21 @@ static ssize_t disk_stats_read(struct gendisk * disk, char *page) ...@@ -445,40 +429,21 @@ static ssize_t disk_stats_read(struct gendisk * disk, char *page)
jiffies_to_msecs(disk_stat_read(disk, io_ticks)), jiffies_to_msecs(disk_stat_read(disk, io_ticks)),
jiffies_to_msecs(disk_stat_read(disk, time_in_queue))); jiffies_to_msecs(disk_stat_read(disk, time_in_queue)));
} }
static struct disk_attribute disk_attr_uevent = {
.attr = {.name = "uevent", .mode = S_IWUSR },
.store = disk_uevent_store
};
static struct disk_attribute disk_attr_dev = {
.attr = {.name = "dev", .mode = S_IRUGO },
.show = disk_dev_read
};
static struct disk_attribute disk_attr_range = {
.attr = {.name = "range", .mode = S_IRUGO },
.show = disk_range_read
};
static struct disk_attribute disk_attr_removable = {
.attr = {.name = "removable", .mode = S_IRUGO },
.show = disk_removable_read
};
static struct disk_attribute disk_attr_size = {
.attr = {.name = "size", .mode = S_IRUGO },
.show = disk_size_read
};
static struct disk_attribute disk_attr_capability = {
.attr = {.name = "capability", .mode = S_IRUGO },
.show = disk_capability_read
};
static struct disk_attribute disk_attr_stat = {
.attr = {.name = "stat", .mode = S_IRUGO },
.show = disk_stats_read
};
#ifdef CONFIG_FAIL_MAKE_REQUEST #ifdef CONFIG_FAIL_MAKE_REQUEST
static ssize_t disk_fail_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gendisk *disk = dev_to_disk(dev);
return sprintf(buf, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0);
}
static ssize_t disk_fail_store(struct gendisk * disk, static ssize_t disk_fail_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct gendisk *disk = dev_to_disk(dev);
int i; int i;
if (count > 0 && sscanf(buf, "%d", &i) > 0) { if (count > 0 && sscanf(buf, "%d", &i) > 0) {
...@@ -490,136 +455,100 @@ static ssize_t disk_fail_store(struct gendisk * disk, ...@@ -490,136 +455,100 @@ static ssize_t disk_fail_store(struct gendisk * disk,
return count; return count;
} }
static ssize_t disk_fail_read(struct gendisk * disk, char *page)
{
return sprintf(page, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0);
}
static struct disk_attribute disk_attr_fail = {
.attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR },
.store = disk_fail_store,
.show = disk_fail_read
};
#endif #endif
static struct attribute * default_attrs[] = { static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
&disk_attr_uevent.attr, static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
&disk_attr_dev.attr, static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL);
&disk_attr_range.attr, static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
&disk_attr_removable.attr, static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL);
&disk_attr_size.attr, #ifdef CONFIG_FAIL_MAKE_REQUEST
&disk_attr_stat.attr, static struct device_attribute dev_attr_fail =
&disk_attr_capability.attr, __ATTR(make-it-fail, S_IRUGO|S_IWUSR, disk_fail_show, disk_fail_store);
#endif
static struct attribute *disk_attrs[] = {
&dev_attr_range.attr,
&dev_attr_removable.attr,
&dev_attr_size.attr,
&dev_attr_capability.attr,
&dev_attr_stat.attr,
#ifdef CONFIG_FAIL_MAKE_REQUEST #ifdef CONFIG_FAIL_MAKE_REQUEST
&disk_attr_fail.attr, &dev_attr_fail.attr,
#endif #endif
NULL, NULL
};
static struct attribute_group disk_attr_group = {
.attrs = disk_attrs,
}; };
static void disk_release(struct kobject * kobj) static struct attribute_group *disk_attr_groups[] = {
&disk_attr_group,
NULL
};
static void disk_release(struct device *dev)
{ {
struct gendisk *disk = to_disk(kobj); struct gendisk *disk = dev_to_disk(dev);
kfree(disk->random); kfree(disk->random);
kfree(disk->part); kfree(disk->part);
free_disk_stats(disk); free_disk_stats(disk);
kfree(disk); kfree(disk);
} }
struct class block_class = {
static struct kobj_type ktype_block = { .name = "block",
.release = disk_release,
.sysfs_ops = &disk_sysfs_ops,
.default_attrs = default_attrs,
}; };
extern struct kobj_type ktype_part; struct device_type disk_type = {
.name = "disk",
static int block_uevent_filter(struct kset *kset, struct kobject *kobj) .groups = disk_attr_groups,
{ .release = disk_release,
struct kobj_type *ktype = get_ktype(kobj);
return ((ktype == &ktype_block) || (ktype == &ktype_part));
}
static int block_uevent(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env *env)
{
struct kobj_type *ktype = get_ktype(kobj);
struct device *physdev;
struct gendisk *disk;
struct hd_struct *part;
if (ktype == &ktype_block) {
disk = container_of(kobj, struct gendisk, kobj);
add_uevent_var(env, "MINOR=%u", disk->first_minor);
} else if (ktype == &ktype_part) {
disk = container_of(kobj->parent, struct gendisk, kobj);
part = container_of(kobj, struct hd_struct, kobj);
add_uevent_var(env, "MINOR=%u",
disk->first_minor + part->partno);
} else
return 0;
add_uevent_var(env, "MAJOR=%u", disk->major);
/* add physical device, backing this device */
physdev = disk->driverfs_dev;
if (physdev) {
char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL);
add_uevent_var(env, "PHYSDEVPATH=%s", path);
kfree(path);
if (physdev->bus)
add_uevent_var(env, "PHYSDEVBUS=%s", physdev->bus->name);
if (physdev->driver)
add_uevent_var(env, physdev->driver->name);
}
return 0;
}
static struct kset_uevent_ops block_uevent_ops = {
.filter = block_uevent_filter,
.uevent = block_uevent,
}; };
decl_subsys(block, &ktype_block, &block_uevent_ops);
/* /*
* aggregate disk stat collector. Uses the same stats that the sysfs * aggregate disk stat collector. Uses the same stats that the sysfs
* entries do, above, but makes them available through one seq_file. * entries do, above, but makes them available through one seq_file.
* Watching a few disks may be efficient through sysfs, but watching
* all of them will be more efficient through this interface.
* *
* The output looks suspiciously like /proc/partitions with a bunch of * The output looks suspiciously like /proc/partitions with a bunch of
* extra fields. * extra fields.
*/ */
/* iterator */
static void *diskstats_start(struct seq_file *part, loff_t *pos) static void *diskstats_start(struct seq_file *part, loff_t *pos)
{ {
loff_t k = *pos; loff_t k = *pos;
struct list_head *p; struct device *dev;
mutex_lock(&block_subsys_lock); mutex_lock(&block_class_lock);
list_for_each(p, &block_subsys.list) list_for_each_entry(dev, &block_class.devices, node) {
if (dev->type != &disk_type)
continue;
if (!k--) if (!k--)
return list_entry(p, struct gendisk, kobj.entry); return dev_to_disk(dev);
}
return NULL; return NULL;
} }
static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos) static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos)
{ {
struct list_head *p = ((struct gendisk *)v)->kobj.entry.next; struct gendisk *gp = v;
struct device *dev;
++*pos; ++*pos;
return p==&block_subsys.list ? NULL : list_for_each_entry(dev, &gp->dev.node, node) {
list_entry(p, struct gendisk, kobj.entry); if (&dev->node == &block_class.devices)
return NULL;
if (dev->type == &disk_type)
return dev_to_disk(dev);
}
return NULL;
} }
static void diskstats_stop(struct seq_file *part, void *v) static void diskstats_stop(struct seq_file *part, void *v)
{ {
mutex_unlock(&block_subsys_lock); mutex_unlock(&block_class_lock);
} }
static int diskstats_show(struct seq_file *s, void *v) static int diskstats_show(struct seq_file *s, void *v)
...@@ -629,7 +558,7 @@ static int diskstats_show(struct seq_file *s, void *v) ...@@ -629,7 +558,7 @@ static int diskstats_show(struct seq_file *s, void *v)
int n = 0; int n = 0;
/* /*
if (&sgp->kobj.entry == block_subsys.kset.list.next) if (&gp->dev.kobj.entry == block_class.devices.next)
seq_puts(s, "major minor name" seq_puts(s, "major minor name"
" rio rmerge rsect ruse wio wmerge " " rio rmerge rsect ruse wio wmerge "
"wsect wuse running use aveq" "wsect wuse running use aveq"
...@@ -683,7 +612,7 @@ static void media_change_notify_thread(struct work_struct *work) ...@@ -683,7 +612,7 @@ static void media_change_notify_thread(struct work_struct *work)
* set enviroment vars to indicate which event this is for * set enviroment vars to indicate which event this is for
* so that user space will know to go check the media status. * so that user space will know to go check the media status.
*/ */
kobject_uevent_env(&gd->kobj, KOBJ_CHANGE, envp); kobject_uevent_env(&gd->dev.kobj, KOBJ_CHANGE, envp);
put_device(gd->driverfs_dev); put_device(gd->driverfs_dev);
} }
...@@ -694,6 +623,25 @@ void genhd_media_change_notify(struct gendisk *disk) ...@@ -694,6 +623,25 @@ void genhd_media_change_notify(struct gendisk *disk)
} }
EXPORT_SYMBOL_GPL(genhd_media_change_notify); EXPORT_SYMBOL_GPL(genhd_media_change_notify);
dev_t blk_lookup_devt(const char *name)
{
struct device *dev;
dev_t devt = MKDEV(0, 0);
mutex_lock(&block_class_lock);
list_for_each_entry(dev, &block_class.devices, node) {
if (strcmp(dev->bus_id, name) == 0) {
devt = dev->devt;
break;
}
}
mutex_unlock(&block_class_lock);
return devt;
}
EXPORT_SYMBOL(blk_lookup_devt);
struct gendisk *alloc_disk(int minors) struct gendisk *alloc_disk(int minors)
{ {
return alloc_disk_node(minors, -1); return alloc_disk_node(minors, -1);
...@@ -721,9 +669,10 @@ struct gendisk *alloc_disk_node(int minors, int node_id) ...@@ -721,9 +669,10 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
} }
} }
disk->minors = minors; disk->minors = minors;
kobj_set_kset_s(disk,block_subsys);
kobject_init(&disk->kobj);
rand_initialize_disk(disk); rand_initialize_disk(disk);
disk->dev.class = &block_class;
disk->dev.type = &disk_type;
device_initialize(&disk->dev);
INIT_WORK(&disk->async_notify, INIT_WORK(&disk->async_notify,
media_change_notify_thread); media_change_notify_thread);
} }
...@@ -743,7 +692,7 @@ struct kobject *get_disk(struct gendisk *disk) ...@@ -743,7 +692,7 @@ struct kobject *get_disk(struct gendisk *disk)
owner = disk->fops->owner; owner = disk->fops->owner;
if (owner && !try_module_get(owner)) if (owner && !try_module_get(owner))
return NULL; return NULL;
kobj = kobject_get(&disk->kobj); kobj = kobject_get(&disk->dev.kobj);
if (kobj == NULL) { if (kobj == NULL) {
module_put(owner); module_put(owner);
return NULL; return NULL;
...@@ -757,7 +706,7 @@ EXPORT_SYMBOL(get_disk); ...@@ -757,7 +706,7 @@ EXPORT_SYMBOL(get_disk);
void put_disk(struct gendisk *disk) void put_disk(struct gendisk *disk)
{ {
if (disk) if (disk)
kobject_put(&disk->kobj); kobject_put(&disk->dev.kobj);
} }
EXPORT_SYMBOL(put_disk); EXPORT_SYMBOL(put_disk);
......
...@@ -1862,9 +1862,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) ...@@ -1862,9 +1862,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
init_timer(&q->unplug_timer); init_timer(&q->unplug_timer);
kobject_set_name(&q->kobj, "%s", "queue"); kobject_init(&q->kobj, &queue_ktype);
q->kobj.ktype = &queue_ktype;
kobject_init(&q->kobj);
mutex_init(&q->sysfs_lock); mutex_init(&q->sysfs_lock);
...@@ -4182,9 +4180,8 @@ int blk_register_queue(struct gendisk *disk) ...@@ -4182,9 +4180,8 @@ int blk_register_queue(struct gendisk *disk)
if (!q || !q->request_fn) if (!q || !q->request_fn)
return -ENXIO; return -ENXIO;
q->kobj.parent = kobject_get(&disk->kobj); ret = kobject_add(&q->kobj, kobject_get(&disk->dev.kobj),
"%s", "queue");
ret = kobject_add(&q->kobj);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -4209,6 +4206,6 @@ void blk_unregister_queue(struct gendisk *disk) ...@@ -4209,6 +4206,6 @@ void blk_unregister_queue(struct gendisk *disk)
kobject_uevent(&q->kobj, KOBJ_REMOVE); kobject_uevent(&q->kobj, KOBJ_REMOVE);
kobject_del(&q->kobj); kobject_del(&q->kobj);
kobject_put(&disk->kobj); kobject_put(&disk->dev.kobj);
} }
} }
...@@ -743,7 +743,7 @@ static int __init acpi_bus_init(void) ...@@ -743,7 +743,7 @@ static int __init acpi_bus_init(void)
return -ENODEV; return -ENODEV;
} }
decl_subsys(acpi, NULL, NULL); struct kobject *acpi_kobj;
static int __init acpi_init(void) static int __init acpi_init(void)
{ {
...@@ -755,10 +755,11 @@ static int __init acpi_init(void) ...@@ -755,10 +755,11 @@ static int __init acpi_init(void)
return -ENODEV; return -ENODEV;
} }
result = firmware_register(&acpi_subsys); acpi_kobj = kobject_create_and_add("acpi", firmware_kobj);
if (result < 0) if (!acpi_kobj) {
printk(KERN_WARNING "%s: firmware_register error: %d\n", printk(KERN_WARNING "%s: kset create error\n", __FUNCTION__);
__FUNCTION__, result); acpi_kobj = NULL;
}
result = acpi_bus_init(); result = acpi_bus_init();
......
...@@ -911,7 +911,7 @@ __setup("acpi_irq_balance", acpi_irq_balance_set); ...@@ -911,7 +911,7 @@ __setup("acpi_irq_balance", acpi_irq_balance_set);
/* FIXME: we will remove this interface after all drivers call pci_disable_device */ /* FIXME: we will remove this interface after all drivers call pci_disable_device */
static struct sysdev_class irqrouter_sysdev_class = { static struct sysdev_class irqrouter_sysdev_class = {
set_kset_name("irqrouter"), .name = "irqrouter",
.resume = irqrouter_resume, .resume = irqrouter_resume,
}; };
......
...@@ -58,7 +58,7 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); ...@@ -58,7 +58,7 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
FS Interface (/sys) FS Interface (/sys)
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
static LIST_HEAD(acpi_table_attr_list); static LIST_HEAD(acpi_table_attr_list);
static struct kobject tables_kobj; static struct kobject *tables_kobj;
struct acpi_table_attr { struct acpi_table_attr {
struct bin_attribute attr; struct bin_attribute attr;
...@@ -135,11 +135,9 @@ static int acpi_system_sysfs_init(void) ...@@ -135,11 +135,9 @@ static int acpi_system_sysfs_init(void)
int table_index = 0; int table_index = 0;
int result; int result;
tables_kobj.parent = &acpi_subsys.kobj; tables_kobj = kobject_create_and_add("tables", acpi_kobj);
kobject_set_name(&tables_kobj, "tables"); if (!tables_kobj)
result = kobject_register(&tables_kobj); return -ENOMEM;
if (result)
return result;
do { do {
result = acpi_get_table_by_index(table_index, &table_header); result = acpi_get_table_by_index(table_index, &table_header);
...@@ -153,7 +151,7 @@ static int acpi_system_sysfs_init(void) ...@@ -153,7 +151,7 @@ static int acpi_system_sysfs_init(void)
acpi_table_attr_init(table_attr, table_header); acpi_table_attr_init(table_attr, table_header);
result = result =
sysfs_create_bin_file(&tables_kobj, sysfs_create_bin_file(tables_kobj,
&table_attr->attr); &table_attr->attr);
if (result) { if (result) {
kfree(table_attr); kfree(table_attr);
...@@ -163,6 +161,7 @@ static int acpi_system_sysfs_init(void) ...@@ -163,6 +161,7 @@ static int acpi_system_sysfs_init(void)
&acpi_table_attr_list); &acpi_table_attr_list);
} }
} while (!result); } while (!result);
kobject_uevent(tables_kobj, KOBJ_ADD);
return 0; return 0;
} }
......
...@@ -11,6 +11,9 @@ obj-$(CONFIG_FW_LOADER) += firmware_class.o ...@@ -11,6 +11,9 @@ obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o obj-$(CONFIG_NUMA) += node.o
obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o
obj-$(CONFIG_SMP) += topology.o obj-$(CONFIG_SMP) += topology.o
ifeq ($(CONFIG_SYSFS),y)
obj-$(CONFIG_MODULES) += module.o
endif
obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
ifeq ($(CONFIG_DEBUG_DRIVER),y) ifeq ($(CONFIG_DEBUG_DRIVER),y)
......
...@@ -61,7 +61,7 @@ attribute_container_classdev_to_container(struct class_device *classdev) ...@@ -61,7 +61,7 @@ attribute_container_classdev_to_container(struct class_device *classdev)
} }
EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container); EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container);
static struct list_head attribute_container_list; static LIST_HEAD(attribute_container_list);
static DEFINE_MUTEX(attribute_container_mutex); static DEFINE_MUTEX(attribute_container_mutex);
...@@ -429,10 +429,3 @@ attribute_container_find_class_device(struct attribute_container *cont, ...@@ -429,10 +429,3 @@ attribute_container_find_class_device(struct attribute_container *cont,
return cdev; return cdev;
} }
EXPORT_SYMBOL_GPL(attribute_container_find_class_device); EXPORT_SYMBOL_GPL(attribute_container_find_class_device);
int __init
attribute_container_init(void)
{
INIT_LIST_HEAD(&attribute_container_list);
return 0;
}
/* initialisation functions */ /**
* struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.
*
* @subsys - the struct kset that defines this bus. This is the main kobject
* @drivers_kset - the list of drivers associated with this bus
* @devices_kset - the list of devices associated with this bus
* @klist_devices - the klist to iterate over the @devices_kset
* @klist_drivers - the klist to iterate over the @drivers_kset
* @bus_notifier - the bus notifier list for anything that cares about things
* on this bus.
* @bus - pointer back to the struct bus_type that this structure is associated
* with.
*
* This structure is the one that is the actual kobject allowing struct
* bus_type to be statically allocated safely. Nothing outside of the driver
* core should ever touch these fields.
*/
struct bus_type_private {
struct kset subsys;
struct kset *drivers_kset;
struct kset *devices_kset;
struct klist klist_devices;
struct klist klist_drivers;
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
struct bus_type *bus;
};
struct driver_private {
struct kobject kobj;
struct klist klist_devices;
struct klist_node knode_bus;
struct module_kobject *mkobj;
struct device_driver *driver;
};
#define to_driver(obj) container_of(obj, struct driver_private, kobj)
/* initialisation functions */
extern int devices_init(void); extern int devices_init(void);
extern int buses_init(void); extern int buses_init(void);
extern int classes_init(void); extern int classes_init(void);
...@@ -13,17 +49,16 @@ static inline int hypervisor_init(void) { return 0; } ...@@ -13,17 +49,16 @@ static inline int hypervisor_init(void) { return 0; }
extern int platform_bus_init(void); extern int platform_bus_init(void);
extern int system_bus_init(void); extern int system_bus_init(void);
extern int cpu_dev_init(void); extern int cpu_dev_init(void);
extern int attribute_container_init(void);
extern int bus_add_device(struct device * dev); extern int bus_add_device(struct device *dev);
extern void bus_attach_device(struct device * dev); extern void bus_attach_device(struct device *dev);
extern void bus_remove_device(struct device * dev); extern void bus_remove_device(struct device *dev);
extern int bus_add_driver(struct device_driver *); extern int bus_add_driver(struct device_driver *drv);
extern void bus_remove_driver(struct device_driver *); extern void bus_remove_driver(struct device_driver *drv);
extern void driver_detach(struct device_driver * drv); extern void driver_detach(struct device_driver *drv);
extern int driver_probe_device(struct device_driver *, struct device *); extern int driver_probe_device(struct device_driver *drv, struct device *dev);
extern void sysdev_shutdown(void); extern void sysdev_shutdown(void);
extern int sysdev_suspend(pm_message_t state); extern int sysdev_suspend(pm_message_t state);
...@@ -44,4 +79,13 @@ extern char *make_class_name(const char *name, struct kobject *kobj); ...@@ -44,4 +79,13 @@ extern char *make_class_name(const char *name, struct kobject *kobj);
extern int devres_release_all(struct device *dev); extern int devres_release_all(struct device *dev);
extern struct kset devices_subsys; extern struct kset *devices_kset;
#if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS)
extern void module_add_driver(struct module *mod, struct device_driver *drv);
extern void module_remove_driver(struct device_driver *drv);
#else
static inline void module_add_driver(struct module *mod,
struct device_driver *drv) { }
static inline void module_remove_driver(struct device_driver *drv) { }
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "base.h" #include "base.h"
struct sysdev_class cpu_sysdev_class = { struct sysdev_class cpu_sysdev_class = {
set_kset_name("cpu"), .name = "cpu",
}; };
EXPORT_SYMBOL(cpu_sysdev_class); EXPORT_SYMBOL(cpu_sysdev_class);
......
/* /*
* drivers/base/dd.c - The core device/driver interactions. * drivers/base/dd.c - The core device/driver interactions.
* *
* This file contains the (sometimes tricky) code that controls the * This file contains the (sometimes tricky) code that controls the
* interactions between devices and drivers, which primarily includes * interactions between devices and drivers, which primarily includes
* driver binding and unbinding. * driver binding and unbinding.
* *
* All of this code used to exist in drivers/base/bus.c, but was * All of this code used to exist in drivers/base/bus.c, but was
* relocated to here in the name of compartmentalization (since it wasn't * relocated to here in the name of compartmentalization (since it wasn't
* strictly code just for the 'struct bus_type'. * strictly code just for the 'struct bus_type'.
* *
* Copyright (c) 2002-5 Patrick Mochel * Copyright (c) 2002-5 Patrick Mochel
* Copyright (c) 2002-3 Open Source Development Labs * Copyright (c) 2002-3 Open Source Development Labs
* Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
* Copyright (c) 2007 Novell Inc.
* *
* This file is released under the GPLv2 * This file is released under the GPLv2
*/ */
#include <linux/device.h> #include <linux/device.h>
...@@ -23,8 +25,6 @@ ...@@ -23,8 +25,6 @@
#include "base.h" #include "base.h"
#include "power/power.h" #include "power/power.h"
#define to_drv(node) container_of(node, struct device_driver, kobj.entry)
static void driver_bound(struct device *dev) static void driver_bound(struct device *dev)
{ {
...@@ -34,27 +34,27 @@ static void driver_bound(struct device *dev) ...@@ -34,27 +34,27 @@ static void driver_bound(struct device *dev)
return; return;
} }
pr_debug("bound device '%s' to driver '%s'\n", pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->bus_id,
dev->bus_id, dev->driver->name); __FUNCTION__, dev->driver->name);
if (dev->bus) if (dev->bus)
blocking_notifier_call_chain(&dev->bus->bus_notifier, blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_BOUND_DRIVER, dev); BUS_NOTIFY_BOUND_DRIVER, dev);
klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); klist_add_tail(&dev->knode_driver, &dev->driver->p->klist_devices);
} }
static int driver_sysfs_add(struct device *dev) static int driver_sysfs_add(struct device *dev)
{ {
int ret; int ret;
ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
kobject_name(&dev->kobj)); kobject_name(&dev->kobj));
if (ret == 0) { if (ret == 0) {
ret = sysfs_create_link(&dev->kobj, &dev->driver->kobj, ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
"driver"); "driver");
if (ret) if (ret)
sysfs_remove_link(&dev->driver->kobj, sysfs_remove_link(&dev->driver->p->kobj,
kobject_name(&dev->kobj)); kobject_name(&dev->kobj));
} }
return ret; return ret;
...@@ -65,24 +65,24 @@ static void driver_sysfs_remove(struct device *dev) ...@@ -65,24 +65,24 @@ static void driver_sysfs_remove(struct device *dev)
struct device_driver *drv = dev->driver; struct device_driver *drv = dev->driver;
if (drv) { if (drv) {
sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); sysfs_remove_link(&drv->p->kobj, kobject_name(&dev->kobj));
sysfs_remove_link(&dev->kobj, "driver"); sysfs_remove_link(&dev->kobj, "driver");
} }
} }
/** /**
* device_bind_driver - bind a driver to one device. * device_bind_driver - bind a driver to one device.
* @dev: device. * @dev: device.
* *
* Allow manual attachment of a driver to a device. * Allow manual attachment of a driver to a device.
* Caller must have already set @dev->driver. * Caller must have already set @dev->driver.
* *
* Note that this does not modify the bus reference count * Note that this does not modify the bus reference count
* nor take the bus's rwsem. Please verify those are accounted * nor take the bus's rwsem. Please verify those are accounted
* for before calling this. (It is ok to call with no other effort * for before calling this. (It is ok to call with no other effort
* from a driver's probe() method.) * from a driver's probe() method.)
* *
* This function must be called with @dev->sem held. * This function must be called with @dev->sem held.
*/ */
int device_bind_driver(struct device *dev) int device_bind_driver(struct device *dev)
{ {
...@@ -93,6 +93,7 @@ int device_bind_driver(struct device *dev) ...@@ -93,6 +93,7 @@ int device_bind_driver(struct device *dev)
driver_bound(dev); driver_bound(dev);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(device_bind_driver);
static atomic_t probe_count = ATOMIC_INIT(0); static atomic_t probe_count = ATOMIC_INIT(0);
static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
...@@ -102,8 +103,8 @@ static int really_probe(struct device *dev, struct device_driver *drv) ...@@ -102,8 +103,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
int ret = 0; int ret = 0;
atomic_inc(&probe_count); atomic_inc(&probe_count);
pr_debug("%s: Probing driver %s with device %s\n", pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
drv->bus->name, drv->name, dev->bus_id); drv->bus->name, __FUNCTION__, drv->name, dev->bus_id);
WARN_ON(!list_empty(&dev->devres_head)); WARN_ON(!list_empty(&dev->devres_head));
dev->driver = drv; dev->driver = drv;
...@@ -125,8 +126,8 @@ static int really_probe(struct device *dev, struct device_driver *drv) ...@@ -125,8 +126,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
driver_bound(dev); driver_bound(dev);
ret = 1; ret = 1;
pr_debug("%s: Bound Device %s to Driver %s\n", pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
drv->bus->name, dev->bus_id, drv->name); drv->bus->name, __FUNCTION__, dev->bus_id, drv->name);
goto done; goto done;
probe_failed: probe_failed:
...@@ -183,7 +184,7 @@ int driver_probe_done(void) ...@@ -183,7 +184,7 @@ int driver_probe_done(void)
* This function must be called with @dev->sem held. When called for a * This function must be called with @dev->sem held. When called for a
* USB interface, @dev->parent->sem must be held as well. * USB interface, @dev->parent->sem must be held as well.
*/ */
int driver_probe_device(struct device_driver * drv, struct device * dev) int driver_probe_device(struct device_driver *drv, struct device *dev)
{ {
int ret = 0; int ret = 0;
...@@ -192,8 +193,8 @@ int driver_probe_device(struct device_driver * drv, struct device * dev) ...@@ -192,8 +193,8 @@ int driver_probe_device(struct device_driver * drv, struct device * dev)
if (drv->bus->match && !drv->bus->match(dev, drv)) if (drv->bus->match && !drv->bus->match(dev, drv))
goto done; goto done;
pr_debug("%s: Matched Device %s with Driver %s\n", pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, dev->bus_id, drv->name); drv->bus->name, __FUNCTION__, dev->bus_id, drv->name);
ret = really_probe(dev, drv); ret = really_probe(dev, drv);
...@@ -201,27 +202,27 @@ int driver_probe_device(struct device_driver * drv, struct device * dev) ...@@ -201,27 +202,27 @@ int driver_probe_device(struct device_driver * drv, struct device * dev)
return ret; return ret;
} }
static int __device_attach(struct device_driver * drv, void * data) static int __device_attach(struct device_driver *drv, void *data)
{ {
struct device * dev = data; struct device *dev = data;
return driver_probe_device(drv, dev); return driver_probe_device(drv, dev);
} }
/** /**
* device_attach - try to attach device to a driver. * device_attach - try to attach device to a driver.
* @dev: device. * @dev: device.
* *
* Walk the list of drivers that the bus has and call * Walk the list of drivers that the bus has and call
* driver_probe_device() for each pair. If a compatible * driver_probe_device() for each pair. If a compatible
* pair is found, break out and return. * pair is found, break out and return.
* *
* Returns 1 if the device was bound to a driver; * Returns 1 if the device was bound to a driver;
* 0 if no matching device was found; * 0 if no matching device was found;
* -ENODEV if the device is not registered. * -ENODEV if the device is not registered.
* *
* When called for a USB interface, @dev->parent->sem must be held. * When called for a USB interface, @dev->parent->sem must be held.
*/ */
int device_attach(struct device * dev) int device_attach(struct device *dev)
{ {
int ret = 0; int ret = 0;
...@@ -240,10 +241,11 @@ int device_attach(struct device * dev) ...@@ -240,10 +241,11 @@ int device_attach(struct device * dev)
up(&dev->sem); up(&dev->sem);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(device_attach);
static int __driver_attach(struct device * dev, void * data) static int __driver_attach(struct device *dev, void *data)
{ {
struct device_driver * drv = data; struct device_driver *drv = data;
/* /*
* Lock device and try to bind to it. We drop the error * Lock device and try to bind to it. We drop the error
...@@ -268,35 +270,35 @@ static int __driver_attach(struct device * dev, void * data) ...@@ -268,35 +270,35 @@ static int __driver_attach(struct device * dev, void * data)
} }
/** /**
* driver_attach - try to bind driver to devices. * driver_attach - try to bind driver to devices.
* @drv: driver. * @drv: driver.
* *
* Walk the list of devices that the bus has on it and try to * Walk the list of devices that the bus has on it and try to
* match the driver with each one. If driver_probe_device() * match the driver with each one. If driver_probe_device()
* returns 0 and the @dev->driver is set, we've found a * returns 0 and the @dev->driver is set, we've found a
* compatible pair. * compatible pair.
*/ */
int driver_attach(struct device_driver * drv) int driver_attach(struct device_driver *drv)
{ {
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
} }
EXPORT_SYMBOL_GPL(driver_attach);
/* /*
* __device_release_driver() must be called with @dev->sem held. * __device_release_driver() must be called with @dev->sem held.
* When called for a USB interface, @dev->parent->sem must be held as well. * When called for a USB interface, @dev->parent->sem must be held as well.
*/ */
static void __device_release_driver(struct device * dev) static void __device_release_driver(struct device *dev)
{ {
struct device_driver * drv; struct device_driver *drv;
drv = get_driver(dev->driver); drv = dev->driver;
if (drv) { if (drv) {
driver_sysfs_remove(dev); driver_sysfs_remove(dev);
sysfs_remove_link(&dev->kobj, "driver"); sysfs_remove_link(&dev->kobj, "driver");
klist_remove(&dev->knode_driver);
if (dev->bus) if (dev->bus)
blocking_notifier_call_chain(&dev->bus->bus_notifier, blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_UNBIND_DRIVER, BUS_NOTIFY_UNBIND_DRIVER,
dev); dev);
...@@ -306,18 +308,18 @@ static void __device_release_driver(struct device * dev) ...@@ -306,18 +308,18 @@ static void __device_release_driver(struct device * dev)
drv->remove(dev); drv->remove(dev);
devres_release_all(dev); devres_release_all(dev);
dev->driver = NULL; dev->driver = NULL;
put_driver(drv); klist_remove(&dev->knode_driver);
} }
} }
/** /**
* device_release_driver - manually detach device from driver. * device_release_driver - manually detach device from driver.
* @dev: device. * @dev: device.
* *
* Manually detach device from driver. * Manually detach device from driver.
* When called for a USB interface, @dev->parent->sem must be held. * When called for a USB interface, @dev->parent->sem must be held.
*/ */
void device_release_driver(struct device * dev) void device_release_driver(struct device *dev)
{ {
/* /*
* If anyone calls device_release_driver() recursively from * If anyone calls device_release_driver() recursively from
...@@ -328,26 +330,26 @@ void device_release_driver(struct device * dev) ...@@ -328,26 +330,26 @@ void device_release_driver(struct device * dev)
__device_release_driver(dev); __device_release_driver(dev);
up(&dev->sem); up(&dev->sem);
} }
EXPORT_SYMBOL_GPL(device_release_driver);
/** /**
* driver_detach - detach driver from all devices it controls. * driver_detach - detach driver from all devices it controls.
* @drv: driver. * @drv: driver.
*/ */
void driver_detach(struct device_driver * drv) void driver_detach(struct device_driver *drv)
{ {
struct device * dev; struct device *dev;
for (;;) { for (;;) {
spin_lock(&drv->klist_devices.k_lock); spin_lock(&drv->p->klist_devices.k_lock);
if (list_empty(&drv->klist_devices.k_list)) { if (list_empty(&drv->p->klist_devices.k_list)) {
spin_unlock(&drv->klist_devices.k_lock); spin_unlock(&drv->p->klist_devices.k_lock);
break; break;
} }
dev = list_entry(drv->klist_devices.k_list.prev, dev = list_entry(drv->p->klist_devices.k_list.prev,
struct device, knode_driver.n_node); struct device, knode_driver.n_node);
get_device(dev); get_device(dev);
spin_unlock(&drv->klist_devices.k_lock); spin_unlock(&drv->p->klist_devices.k_lock);
if (dev->parent) /* Needed for USB */ if (dev->parent) /* Needed for USB */
down(&dev->parent->sem); down(&dev->parent->sem);
...@@ -360,9 +362,3 @@ void driver_detach(struct device_driver * drv) ...@@ -360,9 +362,3 @@ void driver_detach(struct device_driver * drv)
put_device(dev); put_device(dev);
} }
} }
EXPORT_SYMBOL_GPL(device_bind_driver);
EXPORT_SYMBOL_GPL(device_release_driver);
EXPORT_SYMBOL_GPL(device_attach);
EXPORT_SYMBOL_GPL(driver_attach);
此差异已折叠。
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
* *
* Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Patrick Mochel
* Copyright (c) 2002-3 Open Source Development Labs * Copyright (c) 2002-3 Open Source Development Labs
* Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
* Copyright (c) 2007 Novell Inc.
* *
* This file is released under the GPLv2 * This file is released under the GPLv2
*
*/ */
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -15,23 +15,13 @@ ...@@ -15,23 +15,13 @@
#include "base.h" #include "base.h"
static decl_subsys(firmware, NULL, NULL); struct kobject *firmware_kobj;
EXPORT_SYMBOL_GPL(firmware_kobj);
int firmware_register(struct kset *s)
{
kobj_set_kset_s(s, firmware_subsys);
return subsystem_register(s);
}
void firmware_unregister(struct kset *s)
{
subsystem_unregister(s);
}
int __init firmware_init(void) int __init firmware_init(void)
{ {
return subsystem_register(&firmware_subsys); firmware_kobj = kobject_create_and_add("firmware", NULL);
if (!firmware_kobj)
return -ENOMEM;
return 0;
} }
EXPORT_SYMBOL_GPL(firmware_register);
EXPORT_SYMBOL_GPL(firmware_unregister);
...@@ -2,19 +2,23 @@ ...@@ -2,19 +2,23 @@
* hypervisor.c - /sys/hypervisor subsystem. * hypervisor.c - /sys/hypervisor subsystem.
* *
* Copyright (C) IBM Corp. 2006 * Copyright (C) IBM Corp. 2006
* Copyright (C) 2007 Greg Kroah-Hartman <gregkh@suse.de>
* Copyright (C) 2007 Novell Inc.
* *
* This file is released under the GPLv2 * This file is released under the GPLv2
*/ */
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/device.h> #include <linux/device.h>
#include "base.h" #include "base.h"
decl_subsys(hypervisor, NULL, NULL); struct kobject *hypervisor_kobj;
EXPORT_SYMBOL_GPL(hypervisor_subsys); EXPORT_SYMBOL_GPL(hypervisor_kobj);
int __init hypervisor_init(void) int __init hypervisor_init(void)
{ {
return subsystem_register(&hypervisor_subsys); hypervisor_kobj = kobject_create_and_add("hypervisor", NULL);
if (!hypervisor_kobj)
return -ENOMEM;
return 0;
} }
/* /*
*
* Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Patrick Mochel
* Copyright (c) 2002-3 Open Source Development Labs * Copyright (c) 2002-3 Open Source Development Labs
* *
* This file is released under the GPLv2 * This file is released under the GPLv2
*
*/ */
#include <linux/device.h> #include <linux/device.h>
...@@ -14,12 +12,11 @@ ...@@ -14,12 +12,11 @@
#include "base.h" #include "base.h"
/** /**
* driver_init - initialize driver model. * driver_init - initialize driver model.
* *
* Call the driver model init functions to initialize their * Call the driver model init functions to initialize their
* subsystems. Called early from init/main.c. * subsystems. Called early from init/main.c.
*/ */
void __init driver_init(void) void __init driver_init(void)
{ {
/* These are the core pieces */ /* These are the core pieces */
...@@ -36,5 +33,4 @@ void __init driver_init(void) ...@@ -36,5 +33,4 @@ void __init driver_init(void)
system_bus_init(); system_bus_init();
cpu_dev_init(); cpu_dev_init();
memory_dev_init(); memory_dev_init();
attribute_container_init();
} }
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#define MEMORY_CLASS_NAME "memory" #define MEMORY_CLASS_NAME "memory"
static struct sysdev_class memory_sysdev_class = { static struct sysdev_class memory_sysdev_class = {
set_kset_name(MEMORY_CLASS_NAME), .name = MEMORY_CLASS_NAME,
}; };
static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj) static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj)
......
/*
* module.c - module sysfs fun for drivers
*
* This file is released under the GPLv2
*
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/string.h>
#include "base.h"
static char *make_driver_name(struct device_driver *drv)
{
char *driver_name;
driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2,
GFP_KERNEL);
if (!driver_name)
return NULL;
sprintf(driver_name, "%s:%s", drv->bus->name, drv->name);
return driver_name;
}
static void module_create_drivers_dir(struct module_kobject *mk)
{
if (!mk || mk->drivers_dir)
return;
mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj);
}
void module_add_driver(struct module *mod, struct device_driver *drv)
{
char *driver_name;
int no_warn;
struct module_kobject *mk = NULL;
if (!drv)
return;
if (mod)
mk = &mod->mkobj;
else if (drv->mod_name) {
struct kobject *mkobj;
/* Lookup built-in module entry in /sys/modules */
mkobj = kset_find_obj(module_kset, drv->mod_name);
if (mkobj) {
mk = container_of(mkobj, struct module_kobject, kobj);
/* remember our module structure */
drv->p->mkobj = mk;
/* kset_find_obj took a reference */
kobject_put(mkobj);
}
}
if (!mk)
return;
/* Don't check return codes; these calls are idempotent */
no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module");
driver_name = make_driver_name(drv);
if (driver_name) {
module_create_drivers_dir(mk);
no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,
driver_name);
kfree(driver_name);
}
}
void module_remove_driver(struct device_driver *drv)
{
struct module_kobject *mk = NULL;
char *driver_name;
if (!drv)
return;
sysfs_remove_link(&drv->p->kobj, "module");
if (drv->owner)
mk = &drv->owner->mkobj;
else if (drv->p->mkobj)
mk = drv->p->mkobj;
if (mk && mk->drivers_dir) {
driver_name = make_driver_name(drv);
if (driver_name) {
sysfs_remove_link(mk->drivers_dir, driver_name);
kfree(driver_name);
}
}
}
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <linux/device.h> #include <linux/device.h>
static struct sysdev_class node_class = { static struct sysdev_class node_class = {
set_kset_name("node"), .name = "node",
}; };
......
此差异已折叠。
obj-y := shutdown.o
obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM) += sysfs.o
obj-$(CONFIG_PM_SLEEP) += main.o obj-$(CONFIG_PM_SLEEP) += main.o
obj-$(CONFIG_PM_TRACE) += trace.o obj-$(CONFIG_PM_TRACE) += trace.o
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册