From 43cc71eed1250755986da4c0f9898f9a635cb3bf Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 18 Aug 2007 04:40:39 +0200 Subject: platform: prefix MODALIAS with "platform:" Prefix platform modalias strings with "platform:", which modprobe config to blacklist alias resolving if userspace configures it. Send uevents for all platform devices. Add MODULE_ALIAS's to: pxa2xx_pcmcia, ds1742 and pcspkr to trigger module autoloading by userspace. $ modinfo pcspkr alias: platform:pcspkr license: GPL description: PC Speaker beeper driver ... $ modprobe -n -v platform:pcspkr insmod /lib/modules/2.6.23-rc3-g28e8351a-dirty/kernel/drivers/input/misc/pcspkr.ko Signed-off-by: Kay Sievers Cc: David Brownell Cc: Atsushi Nemoto Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 869ff8c..9bfc434 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -160,11 +160,6 @@ static void platform_device_release(struct device *dev) * * Create a platform device object which can have other objects attached * to it, and which will have attached objects freed when it is released. - * - * This device will be marked as not supporting hotpluggable drivers; no - * device add/remove uevents will be generated. In the unusual case that - * the device isn't being dynamically allocated as a legacy "probe the - * hardware" driver, infrastructure code should reverse this marking. */ struct platform_device *platform_device_alloc(const char *name, unsigned int id) { @@ -177,12 +172,6 @@ struct platform_device *platform_device_alloc(const char *name, unsigned int id) pa->pdev.id = id; device_initialize(&pa->pdev.dev); pa->pdev.dev.release = platform_device_release; - - /* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in - * legacy probe-the-hardware drivers, which don't properly split - * out device enumeration logic from drivers. - */ - pa->pdev.dev.uevent_suppress = 1; } return pa ? &pa->pdev : NULL; @@ -530,7 +519,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a, char *buf) { struct platform_device *pdev = to_platform_device(dev); - int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name); + int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; } @@ -546,7 +535,7 @@ static int platform_uevent(struct device *dev, char **envp, int num_envp, struct platform_device *pdev = to_platform_device(dev); envp[0] = buffer; - snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name); + snprintf(buffer, buffer_size, "MODALIAS=platform:%s", pdev->name); return 0; } diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 906bf5e..e1a4402 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -23,6 +23,7 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("PC Speaker beeper driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pcspkr"); #ifdef CONFIG_X86 /* Use the global PIT lock ! */ diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index 383107b..f6722ba 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c @@ -175,7 +175,6 @@ static int __init mst_pcmcia_init(void) if (!mst_pcmcia_device) return -ENOMEM; - mst_pcmcia_device->dev.uevent_suppress = 0; mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops; ret = platform_device_add(mst_pcmcia_device); @@ -195,3 +194,4 @@ fs_initcall(mst_pcmcia_init); module_exit(mst_pcmcia_exit); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index a2daa3f..d5c33bd 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -261,7 +261,6 @@ static int __init sharpsl_pcmcia_init(void) if (!sharpsl_pcmcia_device) return -ENOMEM; - sharpsl_pcmcia_device->dev.uevent_suppress = 0; sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev; @@ -284,3 +283,4 @@ module_exit(sharpsl_pcmcia_exit); MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); -- cgit v0.10.2 From 3b6662f192fc521b9657f63e68d20ec99979dae6 Mon Sep 17 00:00:00 2001 From: Tsugikazu Shibata Date: Tue, 25 Sep 2007 01:54:26 +0900 Subject: HOWTO: update ja_JP/HOWTO with latest changes Here is another sync patch of Documentation/ja_JP/HOWTO Japanese developer sent me some cosmetic changes and also follow changes of HOWTO Cross reference URL (sosdg.org/qiyong/lxr) known_regression explanations on kernel dev. process Signed-off-by: Tsugikazu Shibata Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/ja_JP/HOWTO b/Documentation/ja_JP/HOWTO index 9f08dab..d9d832c 100644 --- a/Documentation/ja_JP/HOWTO +++ b/Documentation/ja_JP/HOWTO @@ -1,4 +1,4 @@ -NOTE: +NOTE: This is a version of Documentation/HOWTO translated into Japanese. This document is maintained by Tsugikazu Shibata and the JF Project team . @@ -11,14 +11,14 @@ for non English (read: Japanese) speakers and is not intended as a fork. So if you have any comments or updates for this file, please try to update the original English file first. -Last Updated: 2007/07/18 +Last Updated: 2007/09/23 ================================== これは、 -linux-2.6.22/Documentation/HOWTO +linux-2.6.23/Documentation/HOWTO の和訳です。 翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ > -翻訳日: 2007/07/16 +翻訳日: 2007/09/19 翻訳者: Tsugikazu Shibata 校正者: 松倉さん 小林 雅典さん (Masanori Kobayasi) @@ -27,6 +27,7 @@ linux-2.6.22/Documentation/HOWTO 野口さん (Kenji Noguchi) 河内さん (Takayoshi Kochi) 岩本さん (iwamoto) + 内田さん (Satoshi Uchida) ================================== Linux カーネル開発のやり方 @@ -40,7 +41,7 @@ Linux カーネル開発コミュニティと共に活動するやり方を学 手助けになります。 もし、このドキュメントのどこかが古くなっていた場合には、このドキュメン -トの最後にリストしたメンテナーにパッチを送ってください。 +トの最後にリストしたメンテナにパッチを送ってください。 はじめに --------- @@ -59,7 +60,7 @@ Linux カーネル開発コミュニティと共に活動するやり方を学 ネル開発者には必要です。アーキテクチャ向けの低レベル部分の開発をするの でなければ、(どんなアーキテクチャでも)アセンブリ(訳注: 言語)は必要あり ません。以下の本は、C 言語の十分な知識や何年もの経験に取って代わるもの -ではありませんが、少なくともリファレンスとしてはいい本です。 +ではありませんが、少なくともリファレンスとしては良い本です。 - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall] -『プログラミング言語C第2版』(B.W. カーニハン/D.M. リッチー著 石田晴久訳) [共立出版] - "Practical C Programming" by Steve Oualline [O'Reilly] @@ -76,7 +77,7 @@ Linux カーネル開発コミュニティと共に活動するやり方を学 ときどき、カーネルがツールチェインや C 言語拡張に置いている前提がどう なっているのかわかりにくいことがあり、また、残念なことに決定的なリファ レンスは存在しません。情報を得るには、gcc の info ページ( info gcc )を -みてください。 +見てください。 あなたは既存の開発コミュニティと一緒に作業する方法を学ぼうとしているこ とに留意してください。そのコミュニティは、コーディング、スタイル、 @@ -92,7 +93,7 @@ Linux カーネル開発コミュニティと共に活動するやり方を学 Linux カーネルのソースコードは GPL ライセンスの下でリリースされていま す。ライセンスの詳細については、ソースツリーのメインディレクトリに存在 -する、COPYING のファイルをみてください。もしライセンスについてさらに質 +する、COPYING のファイルを見てください。もしライセンスについてさらに質 問があれば、Linux Kernel メーリングリストに質問するのではなく、どうぞ 法律家に相談してください。メーリングリストの人達は法律家ではなく、法的 問題については彼らの声明はあてにするべきではありません。 @@ -109,7 +110,8 @@ Linux カーネルソースツリーは幅広い範囲のドキュメントを 新しいドキュメントファイルも追加することを勧めます。 カーネルの変更が、カーネルがユーザ空間に公開しているインターフェイスの 変更を引き起こす場合、その変更を説明するマニュアルページのパッチや情報 -をマニュアルページのメンテナ mtk-manpages@gmx.net に送ることを勧めます。 +をマニュアルページのメンテナ mtk-manpages@gmx.net に送ることを勧めま +す。 以下はカーネルソースツリーに含まれている読んでおくべきファイルの一覧で す- @@ -117,7 +119,7 @@ Linux カーネルソースツリーは幅広い範囲のドキュメントを README このファイルは Linuxカーネルの簡単な背景とカーネルを設定(訳注 configure )し、生成(訳注 build )するために必要なことは何かが書かれ - ています。カーネルに関して初めての人はここからスタートするとよいで + ています。カーネルに関して初めての人はここからスタートすると良いで しょう。 Documentation/Changes @@ -128,7 +130,7 @@ Linux カーネルソースツリーは幅広い範囲のドキュメントを Documentation/CodingStyle これは Linux カーネルのコーディングスタイルと背景にある理由を記述 しています。全ての新しいコードはこのドキュメントにあるガイドライン - に従っていることを期待されています。大部分のメンテナーはこれらのルー + に従っていることを期待されています。大部分のメンテナはこれらのルー ルに従っているものだけを受け付け、多くの人は正しいスタイルのコード だけをレビューします。 @@ -168,16 +170,16 @@ Linux カーネルソースツリーは幅広い範囲のドキュメントを 支援してください。 Documentation/ManagementStyle - このドキュメントは Linux カーネルのメンテナー達がどう行動するか、 + このドキュメントは Linux カーネルのメンテナ達がどう行動するか、 彼らの手法の背景にある共有されている精神について記述しています。こ れはカーネル開発の初心者なら(もしくは、単に興味があるだけの人でも) - 重要です。なぜならこのドキュメントは、カーネルメンテナー達の独特な + 重要です。なぜならこのドキュメントは、カーネルメンテナ達の独特な 行動についての多くの誤解や混乱を解消するからです。 Documentation/stable_kernel_rules.txt このファイルはどのように stable カーネルのリリースが行われるかのルー ルが記述されています。そしてこれらのリリースの中のどこかで変更を取 - り入れてもらいたい場合に何をすればいいかが示されています。 + り入れてもらいたい場合に何をすれば良いかが示されています。 Documentation/kernel-docs.txt   カーネル開発に付随する外部ドキュメントのリストです。もしあなたが @@ -218,9 +220,9 @@ web サイトには、コードの構成、サブシステム、現在存在す ここには、また、カーネルのコンパイルのやり方やパッチの当て方などの間接 的な基本情報も記述されています。 -あなたがどこからスタートしてよいかわからないが、Linux カーネル開発コミュ +あなたがどこからスタートして良いかわからないが、Linux カーネル開発コミュ ニティに参加して何かすることをさがしている場合には、Linux kernel -Janitor's プロジェクトにいけばよいでしょう - +Janitor's プロジェクトにいけば良いでしょう - http://janitor.kernelnewbies.org/ ここはそのようなスタートをするのにうってつけの場所です。ここには、 Linux カーネルソースツリーの中に含まれる、きれいにし、修正しなければな @@ -243,7 +245,7 @@ Linux カーネルソースツリーの中に含まれる、きれいにし、 自己参照方式で、索引がついた web 形式で、ソースコードを参照することが できます。この最新の素晴しいカーネルコードのリポジトリは以下で見つかり ます- - http://sosdg.org/~coywolf/lxr/ + http://sosdg.org/~qiyong/lxr/ 開発プロセス ----------------------- @@ -265,9 +267,9 @@ Linux カーネルの開発プロセスは現在幾つかの異なるメイン 以下のとおり- - 新しいカーネルがリリースされた直後に、2週間の特別期間が設けられ、 - この期間中に、メンテナー達は Linus に大きな差分を送ることができま - す。このような差分は通常 -mm カーネルに数週間含まれてきたパッチで - す。 大きな変更は git(カーネルのソース管理ツール、詳細は + この期間中に、メンテナ達は Linus に大きな差分を送ることができます。 + このような差分は通常 -mm カーネルに数週間含まれてきたパッチです。 + 大きな変更は git(カーネルのソース管理ツール、詳細は http://git.or.cz/ 参照) を使って送るのが好ましいやり方ですが、パッ チファイルの形式のまま送るのでも十分です。 @@ -285,6 +287,10 @@ Linux カーネルの開発プロセスは現在幾つかの異なるメイン に安定した状態にあると判断したときにリリースされます。目標は毎週新 しい -rc カーネルをリリースすることです。 + - 以下の URL で各 -rc リリースに存在する既知の後戻り問題のリスト + が追跡されます- + http://kernelnewbies.org/known_regressions + - このプロセスはカーネルが 「準備ができた」と考えられるまで継続しま す。このプロセスはだいたい 6週間継続します。 @@ -331,8 +337,8 @@ Andrew は個別のサブシステムカーネルツリーとパッチを全て linux-kernel メーリングリストで収集された多数のパッチと同時に一つにま とめます。 このツリーは新機能とパッチが検証される場となります。ある期間の間パッチ -が -mm に入って価値を証明されたら、Andrew やサブシステムメンテナが、メ -インラインへ入れるように Linus にプッシュします。 +が -mm に入って価値を証明されたら、Andrew やサブシステムメンテナが、 +メインラインへ入れるように Linus にプッシュします。 メインカーネルツリーに含めるために Linus に送る前に、すべての新しいパッ チが -mm ツリーでテストされることが強く推奨されます。 @@ -460,7 +466,7 @@ MAINTAINERS ファイルにリストがありますので参照してくださ せん- 彼らはあなたのパッチの行毎にコメントを入れたいので、そのためにはそうす るしかありません。あなたのメールプログラムが空白やタブを圧縮しないよう -に確認した方がいいです。最初の良いテストとしては、自分にメールを送って +に確認した方が良いです。最初の良いテストとしては、自分にメールを送って みて、そのパッチを自分で当ててみることです。もしそれがうまく行かないな ら、あなたのメールプログラムを直してもらうか、正しく動くように変えるべ きです。 @@ -507,14 +513,14 @@ MAINTAINERS ファイルにリストがありますので参照してくださ とも普通のことです。これはあなたのパッチが受け入れられないということで は *ありません*、そしてあなた自身に反対することを意味するのでも *ありま せん*。単に自分のパッチに対して指摘された問題を全て修正して再送すれば -いいのです。 +良いのです。 カーネルコミュニティと企業組織のちがい ----------------------------------------------------------------- カーネルコミュニティは大部分の伝統的な会社の開発環境とは異ったやり方で -動いています。以下は問題を避けるためにできるとよいことののリストです- +動いています。以下は問題を避けるためにできると良いことのリストです- あなたの提案する変更について言うときのうまい言い方: @@ -525,7 +531,7 @@ MAINTAINERS ファイルにリストがありますので参照してくださ - "以下は一連の小さなパッチ群ですが..." - "これは典型的なマシンでの性能を向上させます.." - やめた方がいい悪い言い方: + やめた方が良い悪い言い方: - このやり方で AIX/ptx/Solaris ではできたので、できるはずだ - 私はこれを20年もの間やってきた、だから @@ -575,10 +581,10 @@ Linux カーネルコミュニティは、一度に大量のコードの塊を 1) 小さいパッチはあなたのパッチが適用される見込みを大きくします、カー ネルの人達はパッチが正しいかどうかを確認する時間や労力をかけないか - らです。5行のパッチはメンテナがたった1秒見るだけで適用できます。し - かし、500行のパッチは、正しいことをレビューするのに数時間かかるかも - しれません(時間はパッチのサイズなどにより指数関数に比例してかかりま - す) + らです。5行のパッチはメンテナがたった1秒見るだけで適用できます。 + しかし、500行のパッチは、正しいことをレビューするのに数時間かかるか + もしれません(時間はパッチのサイズなどにより指数関数に比例してかかり + ます) 小さいパッチは何かあったときにデバッグもとても簡単になります。パッ チを1個1個取り除くのは、とても大きなパッチを当てた後に(かつ、何かお @@ -587,23 +593,23 @@ Linux カーネルコミュニティは、一度に大量のコードの塊を 2) 小さいパッチを送るだけでなく、送るまえに、書き直して、シンプルにす る(もしくは、単に順番を変えるだけでも)ことも、とても重要です。 -以下はカーネル開発者の Al Viro のたとえ話しです: +以下はカーネル開発者の Al Viro のたとえ話です: "生徒の数学の宿題を採点する先生のことを考えてみてください、先 - 生は生徒が解に到達するまでの試行錯誤をみたいとは思わないでしょ - う。先生は簡潔な最高の解をみたいのです。良い生徒はこれを知って + 生は生徒が解に到達するまでの試行錯誤を見たいとは思わないでしょ + う。先生は簡潔な最高の解を見たいのです。良い生徒はこれを知って おり、そして最終解の前の中間作業を提出することは決してないので す" - カーネル開発でもこれは同じです。メンテナー達とレビューア達は、 - 問題を解決する解の背後になる思考プロセスをみたいとは思いません。 - 彼らは単純であざやかな解決方法をみたいのです。 + カーネル開発でもこれは同じです。メンテナ達とレビューア達は、 + 問題を解決する解の背後になる思考プロセスを見たいとは思いません。 + 彼らは単純であざやかな解決方法を見たいのです。 あざやかな解を説明するのと、コミュニティと共に仕事をし、未解決の仕事を 議論することのバランスをキープするのは難しいかもしれません。 ですから、開発プロセスの早期段階で改善のためのフィードバックをもらうよ -うにするのもいいですが、変更点を小さい部分に分割して全体ではまだ完成し -ていない仕事を(部分的に)取り込んでもらえるようにすることもいいことです。 +うにするのも良いですが、変更点を小さい部分に分割して全体ではまだ完成し +ていない仕事を(部分的に)取り込んでもらえるようにすることも良いことです。 また、でき上がっていないものや、"将来直す" ようなパッチを、本流に含め てもらうように送っても、それは受け付けられないことを理解してください。 @@ -629,7 +635,7 @@ Linux カーネルコミュニティは、一度に大量のコードの塊を - テスト結果 これについて全てがどのようにあるべきかについての詳細は、以下のドキュメ -ントの ChangeLog セクションをみてください- +ントの ChangeLog セクションを見てください- "The Perfect Patch" http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt -- cgit v0.10.2 From 8380770c842faef3001e44662953d64ad9a93663 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 30 Jul 2007 02:28:56 +0200 Subject: Driver core: make sysfs uevent-attributes static Attributes do not have an owner(module) anymore, so there is no need to carry the attributes in every single bus instance. Signed-off-by: Kay Sievers Acked-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 61c6752..ff850d1 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -568,32 +568,29 @@ static void remove_bind_files(struct device_driver *drv) driver_remove_file(drv, &driver_attr_unbind); } +static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe); +static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO, + show_drivers_autoprobe, store_drivers_autoprobe); + static int add_probe_files(struct bus_type *bus) { int retval; - bus->drivers_probe_attr.attr.name = "drivers_probe"; - bus->drivers_probe_attr.attr.mode = S_IWUSR; - bus->drivers_probe_attr.store = store_drivers_probe; - retval = bus_create_file(bus, &bus->drivers_probe_attr); + retval = bus_create_file(bus, &bus_attr_drivers_probe); if (retval) goto out; - bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe"; - bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO; - bus->drivers_autoprobe_attr.show = show_drivers_autoprobe; - bus->drivers_autoprobe_attr.store = store_drivers_autoprobe; - retval = bus_create_file(bus, &bus->drivers_autoprobe_attr); + retval = bus_create_file(bus, &bus_attr_drivers_autoprobe); if (retval) - bus_remove_file(bus, &bus->drivers_probe_attr); + bus_remove_file(bus, &bus_attr_drivers_probe); out: return retval; } static void remove_probe_files(struct bus_type *bus) { - bus_remove_file(bus, &bus->drivers_autoprobe_attr); - bus_remove_file(bus, &bus->drivers_probe_attr); + bus_remove_file(bus, &bus_attr_drivers_autoprobe); + bus_remove_file(bus, &bus_attr_drivers_probe); } #else static inline int add_bind_files(struct device_driver *drv) { return 0; } diff --git a/include/linux/device.h b/include/linux/device.h index 3a38d1f..5d97ca6 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -64,8 +64,6 @@ struct bus_type { struct bus_attribute * bus_attrs; struct device_attribute * dev_attrs; struct driver_attribute * drv_attrs; - struct bus_attribute drivers_autoprobe_attr; - struct bus_attribute drivers_probe_attr; int (*match)(struct device * dev, struct device_driver * drv); int (*uevent)(struct device *dev, char **envp, -- cgit v0.10.2 From 7eff2e7a8b65c25920207324e56611150eb1cd9a Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 14 Aug 2007 15:15:12 +0200 Subject: Driver core: change add_uevent_var to use a struct This changes the uevent buffer functions to use a struct instead of a long list of parameters. It does no longer require the caller to do the proper buffer termination and size accounting, which is currently wrong in some places. It fixes a known bug where parts of the uevent environment are overwritten because of wrong index calculations. Many thanks to Mathieu Desnoyers for finding bugs and improving the error handling. Signed-off-by: Kay Sievers Cc: Mathieu Desnoyers Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c index 5a289e4..a88eba3 100644 --- a/arch/ia64/sn/kernel/tiocx.c +++ b/arch/ia64/sn/kernel/tiocx.c @@ -66,8 +66,7 @@ static int tiocx_match(struct device *dev, struct device_driver *drv) } -static int tiocx_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int tiocx_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c index 89b911e..8f3db32 100644 --- a/arch/powerpc/kernel/of_device.c +++ b/arch/powerpc/kernel/of_device.c @@ -57,26 +57,21 @@ ssize_t of_device_get_modalias(struct of_device *ofdev, return tsize; } -int of_device_uevent(struct device *dev, - char **envp, int num_envp, char *buffer, int buffer_size) +int of_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct of_device *ofdev; const char *compat; - int i = 0, length = 0, seen = 0, cplen, sl; + int seen = 0, cplen, sl; if (!dev) return -ENODEV; ofdev = to_of_device(dev); - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_NAME=%s", ofdev->node->name)) + if (add_uevent_var(env, "OF_NAME=%s", ofdev->node->name)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_TYPE=%s", ofdev->node->type)) + if (add_uevent_var(env, "OF_TYPE=%s", ofdev->node->type)) return -ENOMEM; /* Since the compatible field can contain pretty much anything @@ -85,9 +80,7 @@ int of_device_uevent(struct device *dev, compat = of_get_property(ofdev->node, "compatible", &cplen); while (compat && *compat && cplen > 0) { - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_%d=%s", seen, compat)) + if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat)) return -ENOMEM; sl = strlen (compat) + 1; @@ -96,25 +89,17 @@ int of_device_uevent(struct device *dev, seen++; } - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_N=%d", seen)) + if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen)) return -ENOMEM; /* modalias is trickier, we add it in 2 steps */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=")) + if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; - - sl = of_device_get_modalias(ofdev, &buffer[length-1], - buffer_size-length); - if (sl >= (buffer_size-length)) + sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1], + sizeof(env->buf) - env->buflen); + if (sl >= (sizeof(env->buf) - env->buflen)) return -ENOMEM; - - length += sl; - - envp[i] = NULL; + env->buflen += sl; return 0; } diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index cb22a35..19a5656 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -317,30 +317,20 @@ static int vio_bus_match(struct device *dev, struct device_driver *drv) return (ids != NULL) && (vio_match_device(ids, vio_dev) != NULL); } -static int vio_hotplug(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int vio_hotplug(struct device *dev, struct kobj_uevent_env *env) { const struct vio_dev *vio_dev = to_vio_dev(dev); struct device_node *dn; const char *cp; - int length; - - if (!num_envp) - return -ENOMEM; dn = dev->archdata.of_node; if (!dn) return -ENODEV; - cp = of_get_property(dn, "compatible", &length); + cp = of_get_property(dn, "compatible", NULL); if (!cp) return -ENODEV; - envp[0] = buffer; - length = scnprintf(buffer, buffer_size, "MODALIAS=vio:T%sS%s", - vio_dev->type, cp); - if ((buffer_size - length) <= 0) - return -ENOMEM; - envp[1] = NULL; + add_uevent_var(env, "MODALIAS=vio:T%sS%s", vio_dev->type, cp); return 0; } diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 4bb634a..ea0b2c7 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -437,18 +437,13 @@ static void ps3_system_bus_shutdown(struct device *_dev) dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); } -static int ps3_system_bus_uevent(struct device *_dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int ps3_system_bus_uevent(struct device *_dev, struct kobj_uevent_env *env) { struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); int i = 0, length = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "MODALIAS=ps3:%d", - dev->match_id)) + if (add_uevent_var(env, "MODALIAS=ps3:%d", dev->match_id)) return -ENOMEM; - - envp[i] = NULL; return 0; } diff --git a/block/genhd.c b/block/genhd.c index 3af1e7a..e609996 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -540,61 +540,42 @@ static int block_uevent_filter(struct kset *kset, struct kobject *kobj) return ((ktype == &ktype_block) || (ktype == &ktype_part)); } -static int block_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +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; - int length = 0; - int i = 0; if (ktype == &ktype_block) { disk = container_of(kobj, struct gendisk, kobj); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "MINOR=%u", disk->first_minor); + 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(envp, num_envp, &i, buffer, buffer_size, - &length, "MINOR=%u", + add_uevent_var(env, "MINOR=%u", disk->first_minor + part->partno); } else return 0; - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MAJOR=%u", disk->major); + 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(envp, num_envp, &i, buffer, buffer_size, - &length, "PHYSDEVPATH=%s", path); + add_uevent_var(env, "PHYSDEVPATH=%s", path); kfree(path); if (physdev->bus) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", - physdev->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", physdev->bus->name); if (physdev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", - physdev->driver->name); + add_uevent_var(env, physdev->driver->name); } - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - return 0; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 64620d6..5b4d462 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -319,16 +319,18 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv) return !acpi_match_device_ids(acpi_dev, acpi_drv->ids); } -static int acpi_device_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct acpi_device *acpi_dev = to_acpi_device(dev); + int len; - strcpy(buffer, "MODALIAS="); - if (create_modalias(acpi_dev, buffer + 9, buffer_size - 9) > 0) { - envp[0] = buffer; - envp[1] = NULL; - } + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + len = create_modalias(acpi_dev, &env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len >= (sizeof(env->buf) - env->buflen)) + return -ENOMEM; + env->buflen += len; return 0; } diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 268e301..6b94fb7 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -44,15 +44,12 @@ static int amba_match(struct device *dev, struct device_driver *drv) } #ifdef CONFIG_HOTPLUG -static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz) +static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) { struct amba_device *pcdev = to_amba_device(dev); - int retval = 0, i = 0, len = 0; + int retval = 0; - retval = add_uevent_var(envp, nr_env, &i, - buf, bufsz, &len, - "AMBA_ID=%08x", pcdev->periphid); - envp[i] = NULL; + retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid); return retval; } #else diff --git a/drivers/base/class.c b/drivers/base/class.c index 4d22226..ecd6336 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -180,8 +180,7 @@ static void class_device_create_release(struct class_device *class_dev) /* needed to allow these devices to have parent class devices */ static int class_device_create_uevent(struct class_device *class_dev, - char **envp, int num_envp, - char *buffer, int buffer_size) + struct kobj_uevent_env *env) { pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id); return 0; @@ -403,64 +402,43 @@ static void remove_deprecated_class_device_links(struct class_device *cd) { } #endif -static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int class_uevent(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env) { struct class_device *class_dev = to_class_dev(kobj); struct device *dev = class_dev->dev; - int i = 0; - int length = 0; int retval = 0; pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id); if (MAJOR(class_dev->devt)) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MAJOR=%u", MAJOR(class_dev->devt)); + add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt)); - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MINOR=%u", MINOR(class_dev->devt)); + add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt)); } if (dev) { const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL); if (path) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVPATH=%s", path); + add_uevent_var(env, "PHYSDEVPATH=%s", path); kfree(path); } if (dev->bus) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", dev->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); if (dev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", dev->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); } - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - if (class_dev->uevent) { /* have the class device specific function add its stuff */ - retval = class_dev->uevent(class_dev, envp, num_envp, - buffer, buffer_size); + retval = class_dev->uevent(class_dev, env); if (retval) pr_debug("class_dev->uevent() returned %d\n", retval); } else if (class_dev->class->uevent) { /* have the class specific function add its stuff */ - retval = class_dev->class->uevent(class_dev, envp, num_envp, - buffer, buffer_size); + retval = class_dev->class->uevent(class_dev, env); if (retval) pr_debug("class->uevent() returned %d\n", retval); } diff --git a/drivers/base/core.c b/drivers/base/core.c index ec86d6f..d487c03 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -141,33 +141,23 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) return NULL; } -static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int dev_uevent(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env) { struct device *dev = to_dev(kobj); - int i = 0; - int length = 0; int retval = 0; /* add the major/minor if present */ if (MAJOR(dev->devt)) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MAJOR=%u", MAJOR(dev->devt)); - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MINOR=%u", MINOR(dev->devt)); + add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); + add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); } if (dev->type && dev->type->name) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVTYPE=%s", dev->type->name); + add_uevent_var(env, "DEVTYPE=%s", dev->type->name); if (dev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DRIVER=%s", dev->driver->name); + add_uevent_var(env, "DRIVER=%s", dev->driver->name); #ifdef CONFIG_SYSFS_DEPRECATED if (dev->class) { @@ -181,59 +171,43 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, path = kobject_get_path(&parent->kobj, GFP_KERNEL); if (path) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVPATH=%s", path); + add_uevent_var(env, "PHYSDEVPATH=%s", path); kfree(path); } - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", parent->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name); if (parent->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", parent->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", + parent->driver->name); } } else if (dev->bus) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", dev->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); if (dev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", dev->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); } #endif - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - + /* have the bus specific function add its stuff */ if (dev->bus && dev->bus->uevent) { - /* have the bus specific function add its stuff */ - retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size); + retval = dev->bus->uevent(dev, env); if (retval) pr_debug ("%s: bus uevent() returned %d\n", __FUNCTION__, retval); } + /* have the class specific function add its stuff */ if (dev->class && dev->class->dev_uevent) { - /* have the class specific function add its stuff */ - retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size); + retval = dev->class->dev_uevent(dev, env); if (retval) pr_debug("%s: class uevent() returned %d\n", __FUNCTION__, retval); } + /* have the device type specific fuction add its stuff */ if (dev->type && dev->type->uevent) { - /* have the device type specific fuction add its stuff */ - retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size); + retval = dev->type->uevent(dev, env); if (retval) pr_debug("%s: dev_type uevent() returned %d\n", __FUNCTION__, retval); @@ -253,9 +227,7 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, { struct kobject *top_kobj; struct kset *kset; - char *envp[32]; - char *data = NULL; - char *pos; + struct kobj_uevent_env *env = NULL; int i; size_t count = 0; int retval; @@ -278,26 +250,20 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, if (!kset->uevent_ops->filter(kset, &dev->kobj)) goto out; - data = (char *)get_zeroed_page(GFP_KERNEL); - if (!data) + env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); + if (!env) return -ENOMEM; /* let the kset specific function add its keys */ - pos = data; - memset(envp, 0, sizeof(envp)); - retval = kset->uevent_ops->uevent(kset, &dev->kobj, - envp, ARRAY_SIZE(envp), - pos, PAGE_SIZE); + retval = kset->uevent_ops->uevent(kset, &dev->kobj, env); if (retval) goto out; /* copy keys to file */ - for (i = 0; envp[i]; i++) { - pos = &buf[count]; - count += sprintf(pos, "%s\n", envp[i]); - } + for (i = 0; i < env->envp_idx; i++) + count += sprintf(&buf[count], "%s\n", env->envp[i]); out: - free_page((unsigned long)data); + kfree(env); return count; } diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index b24efd4..4a1b9bf 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -88,19 +88,14 @@ static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store); static void fw_dev_release(struct device *dev); -static int firmware_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) { struct firmware_priv *fw_priv = dev_get_drvdata(dev); - int i = 0, len = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "FIRMWARE=%s", fw_priv->fw_id)) + if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "TIMEOUT=%i", loading_timeout)) + if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout)) return -ENOMEM; - envp[i] = NULL; return 0; } diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 74b9679..cb99dae 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -34,8 +34,7 @@ static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj) return MEMORY_CLASS_NAME; } -static int memory_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int memory_uevent(struct kset *kset, struct kobj_uevent_env *env) { int retval = 0; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 9bfc434..a2e3910 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -529,13 +529,11 @@ static struct device_attribute platform_dev_attrs[] = { __ATTR_NULL, }; -static int platform_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) { struct platform_device *pdev = to_platform_device(dev); - envp[0] = buffer; - snprintf(buffer, buffer_size, "MODALIAS=platform:%s", pdev->name); + add_uevent_var(env, "MODALIAS=platform:%s", pdev->name); return 0; } diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c index d944647..4d4a473 100644 --- a/drivers/eisa/eisa-bus.c +++ b/drivers/eisa/eisa-bus.c @@ -128,16 +128,11 @@ static int eisa_bus_match (struct device *dev, struct device_driver *drv) return 0; } -static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int eisa_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct eisa_device *edev = to_eisa_device(dev); - int i = 0; - int length = 0; - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig); - envp[i] = NULL; + add_uevent_var(env, "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig); return 0; } diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 2b65863..56681b3 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c @@ -130,23 +130,16 @@ static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size) } static int -fw_unit_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env) { struct fw_unit *unit = fw_unit(dev); char modalias[64]; - int length = 0; - int i = 0; get_modalias(unit, modalias, sizeof(modalias)); - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=%s", modalias)) + if (add_uevent_var(env, "MODALIAS=%s", modalias)) return -ENOMEM; - envp[i] = NULL; - return 0; } diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index 59c3b5a..2678098 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -134,14 +134,17 @@ static struct attribute_group* sys_dmi_attribute_groups[] = { NULL }; -static int dmi_dev_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int dmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) { - strcpy(buffer, "MODALIAS="); - get_modalias(buffer+9, buffer_size-9); - envp[0] = buffer; - envp[1] = NULL; - + ssize_t len; + + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + len = get_modalias(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len >= (sizeof(env->buf) - env->buflen)) + return -ENOMEM; + env->buflen += len; return 0; } diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d663e69..910a62d 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -67,20 +67,16 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) #ifdef CONFIG_HOTPLUG /* uevent helps with hotplug: modprobe -q $(MODALIAS) */ -static int i2c_device_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct i2c_client *client = to_i2c_client(dev); - int i = 0, length = 0; /* by definition, legacy drivers can't hotplug */ if (dev->driver || !client->driver_name) return 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=%s", client->driver_name)) + if (add_uevent_var(env, "MODALIAS=%s", client->driver_name)) return -ENOMEM; - envp[i] = NULL; dev_dbg(dev, "uevent\n"); return 0; } diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index e96212c..a96a8b1 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1663,20 +1663,13 @@ static struct device_attribute ide_dev_attrs[] = { __ATTR_NULL }; -static int ide_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ide_uevent(struct device *dev, struct kobj_uevent_env *env) { ide_drive_t *drive = to_ide_device(dev); - int i = 0; - int length = 0; - - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MEDIA=%s", media_string(drive)); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "DRIVENAME=%s", drive->name); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=ide:m-%s", media_string(drive)); - envp[i] = NULL; + + add_uevent_var(env, "MEDIA=%s", media_string(drive)); + add_uevent_var(env, "DRIVENAME=%s", drive->name); + add_uevent_var(env, "MODALIAS=ide:m-%s", media_string(drive)); return 0; } diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 2ffd534..1939fee 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -153,8 +153,7 @@ struct host_info { }; static int nodemgr_bus_match(struct device * dev, struct device_driver * drv); -static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); +static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env); static void nodemgr_resume_ne(struct node_entry *ne); static void nodemgr_remove_ne(struct node_entry *ne); static struct node_entry *find_entry_by_guid(u64 guid); @@ -1160,12 +1159,9 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent #ifdef CONFIG_HOTPLUG -static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env) { struct unit_directory *ud; - int i = 0; - int length = 0; int retval = 0; /* ieee1394:venNmoNspNverN */ char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1]; @@ -1180,9 +1176,7 @@ static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, #define PUT_ENVP(fmt,val) \ do { \ - retval = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &length, \ - fmt, val); \ + retval = add_uevent_var(env, fmt, val); \ if (retval) \ return retval; \ } while (0) @@ -1201,15 +1195,12 @@ do { \ #undef PUT_ENVP - envp[i] = NULL; - return 0; } #else -static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 70b77ae..3d40506 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -434,21 +434,18 @@ static void ib_device_release(struct class_device *cdev) kfree(dev); } -static int ib_device_uevent(struct class_device *cdev, char **envp, - int num_envp, char *buf, int size) +static int ib_device_uevent(struct class_device *cdev, + struct kobj_uevent_env *env) { struct ib_device *dev = container_of(cdev, struct ib_device, class_dev); - int i = 0, len = 0; - if (add_uevent_var(envp, num_envp, &i, buf, size, &len, - "NAME=%s", dev->name)) + if (add_uevent_var(env, "NAME=%s", dev->name)) return -ENOMEM; /* * It would be nice to pass the node GUID with the event... */ - envp[i] = NULL; return 0; } diff --git a/drivers/input/input.c b/drivers/input/input.c index 5fe7555..5dc361c 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -859,87 +859,66 @@ static void input_dev_release(struct device *device) * Input uevent interface - loading event handlers based on * device bitfields. */ -static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, +static int input_add_uevent_bm_var(struct kobj_uevent_env *env, const char *name, unsigned long *bitmap, int max) { - if (*cur_index >= num_envp - 1) - return -ENOMEM; - - envp[*cur_index] = buffer + *cur_len; + int len; - *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name); - if (*cur_len >= buffer_size) + if (add_uevent_var(env, "%s=", name)) return -ENOMEM; - *cur_len += input_print_bitmap(buffer + *cur_len, - max(buffer_size - *cur_len, 0), - bitmap, max, 0) + 1; - if (*cur_len > buffer_size) + len = input_print_bitmap(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen, + bitmap, max, 0); + if (len >= (sizeof(env->buf) - env->buflen)) return -ENOMEM; - (*cur_index)++; + env->buflen += len; return 0; } -static int input_add_uevent_modalias_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, +static int input_add_uevent_modalias_var(struct kobj_uevent_env *env, struct input_dev *dev) { - if (*cur_index >= num_envp - 1) - return -ENOMEM; - - envp[*cur_index] = buffer + *cur_len; + int len; - *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), - "MODALIAS="); - if (*cur_len >= buffer_size) + if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; - *cur_len += input_print_modalias(buffer + *cur_len, - max(buffer_size - *cur_len, 0), - dev, 0) + 1; - if (*cur_len > buffer_size) + len = input_print_modalias(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen, + dev, 0); + if (len >= (sizeof(env->buf) - env->buflen)) return -ENOMEM; - (*cur_index)++; + env->buflen += len; return 0; } #define INPUT_ADD_HOTPLUG_VAR(fmt, val...) \ do { \ - int err = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &len, \ - fmt, val); \ + int err = add_uevent_var(env, fmt, val); \ if (err) \ return err; \ } while (0) #define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max) \ do { \ - int err = input_add_uevent_bm_var(envp, num_envp, &i, \ - buffer, buffer_size, &len, \ - name, bm, max); \ + int err = input_add_uevent_bm_var(env, name, bm, max); \ if (err) \ return err; \ } while (0) #define INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev) \ do { \ - int err = input_add_uevent_modalias_var(envp, \ - num_envp, &i, \ - buffer, buffer_size, &len, \ - dev); \ + int err = input_add_uevent_modalias_var(env, dev); \ if (err) \ return err; \ } while (0) -static int input_dev_uevent(struct device *device, char **envp, - int num_envp, char *buffer, int buffer_size) +static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env) { struct input_dev *dev = to_input_dev(device); - int i = 0; - int len = 0; INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x", dev->id.bustype, dev->id.vendor, @@ -971,7 +950,6 @@ static int input_dev_uevent(struct device *device, char **envp, INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev); - envp[i] = NULL; return 0; } diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 372ca49..b3bc15a 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -876,18 +876,14 @@ static int serio_bus_match(struct device *dev, struct device_driver *drv) #define SERIO_ADD_UEVENT_VAR(fmt, val...) \ do { \ - int err = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &len, \ - fmt, val); \ + int err = add_uevent_var(env, fmt, val); \ if (err) \ return err; \ } while (0) -static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) +static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) { struct serio *serio; - int i = 0; - int len = 0; if (!dev) return -ENODEV; @@ -900,7 +896,6 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra); SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X", serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); - envp[i] = NULL; return 0; } @@ -908,7 +903,7 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf #else -static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) +static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 7a78d6b..2ee3c30 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -905,8 +905,8 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, } -static int pvr2_sysfs_hotplug(struct device *cd,char **envp, - int numenvp,char *buf,int size) +static int pvr2_sysfs_hotplug(struct device *d, + struct kobj_uevent_env *env) { /* Even though we don't do anything here, we still need this function because sysfs will still try to call it. */ diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index d195fb0..8f77949 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -57,16 +57,11 @@ static int tifm_bus_match(struct device *dev, struct device_driver *drv) return 0; } -static int tifm_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int tifm_uevent(struct device *dev, struct kobj_uevent_env *env) { struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); - int i = 0; - int length = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "TIFM_CARD_TYPE=%s", - tifm_media_type_name(sock->type, 1))) + if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1))) return -ENOMEM; return 0; diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 8d6f601..b0c22ca 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -58,12 +58,11 @@ static int mmc_bus_match(struct device *dev, struct device_driver *drv) } static int -mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, - int buf_size) +mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct mmc_card *card = dev_to_mmc_card(dev); const char *type; - int i = 0, length = 0; + int retval = 0; switch (card->type) { case MMC_TYPE_MMC: @@ -80,20 +79,14 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, } if (type) { - if (add_uevent_var(envp, num_envp, &i, - buf, buf_size, &length, - "MMC_TYPE=%s", type)) - return -ENOMEM; + retval = add_uevent_var(env, "MMC_TYPE=%s", type); + if (retval) + return retval; } - if (add_uevent_var(envp, num_envp, &i, - buf, buf_size, &length, - "MMC_NAME=%s", mmc_card_name(card))) - return -ENOMEM; + retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card)); - envp[i] = NULL; - - return 0; + return retval; } static int mmc_bus_probe(struct device *dev) diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 1c97e7d..2b5352a 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -3,12 +3,9 @@ #include #include "pci.h" -int pci_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +int pci_uevent(struct device *dev, struct kobj_uevent_env *env) { struct pci_dev *pdev; - int i = 0; - int length = 0; if (!dev) return -ENODEV; @@ -17,37 +14,24 @@ int pci_uevent(struct device *dev, char **envp, int num_envp, if (!pdev) return -ENODEV; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_CLASS=%04X", pdev->class)) + if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_ID=%04X:%04X", pdev->vendor, pdev->device)) + if (add_uevent_var(env, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, + if (add_uevent_var(env, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_SLOT_NAME=%s", pci_name(pdev))) + if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev))) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", + if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device, (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), (u8)(pdev->class))) return -ENOMEM; - - envp[i] = NULL; - return 0; } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 004bc24..f61be3a 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -532,8 +532,7 @@ void pci_dev_put(struct pci_dev *dev) } #ifndef CONFIG_HOTPLUG -int pci_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +int pci_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 4c36e80..b3a7d5b 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1,7 +1,6 @@ /* Functions internal to the PCI core code */ -extern int pci_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); +extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env); extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); extern void pci_cleanup_rom(struct pci_dev *dev); diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index f8b13f0..a0aca46 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -907,18 +907,14 @@ int pcmcia_insert_card(struct pcmcia_socket *skt) EXPORT_SYMBOL(pcmcia_insert_card); -static int pcmcia_socket_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int pcmcia_socket_uevent(struct device *dev, + struct kobj_uevent_env *env) { struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev); - int i = 0, length = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "SOCKET_NO=%u", s->sock)) + if (add_uevent_var(env, "SOCKET_NO=%u", s->sock)) return -ENOMEM; - envp[i] = NULL; - return 0; } diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index a996071..55baa1f 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1064,11 +1064,10 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { #ifdef CONFIG_HOTPLUG -static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct pcmcia_device *p_dev; - int i, length = 0; + int i; u32 hash[4] = { 0, 0, 0, 0}; if (!dev) @@ -1083,23 +1082,13 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i])); } - i = 0; - - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "SOCKET_NO=%u", - p_dev->socket->sock)) + if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE_NO=%02X", - p_dev->device_no)) + if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" + if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" "pa%08Xpb%08Xpc%08Xpd%08X", p_dev->has_manf_id ? p_dev->manf_id : 0, p_dev->has_card_id ? p_dev->card_id : 0, @@ -1112,15 +1101,12 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, hash[3])) return -ENOMEM; - envp[i] = NULL; - return 0; } #else -static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h index a9880d4..f38ba48 100644 --- a/drivers/power/power_supply.h +++ b/drivers/power/power_supply.h @@ -14,8 +14,7 @@ extern int power_supply_create_attrs(struct power_supply *psy); extern void power_supply_remove_attrs(struct power_supply *psy); -extern int power_supply_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); +extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env); #else diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index de3155b..249f61b 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -195,11 +195,10 @@ static char *kstruprdup(const char *str, gfp_t gfp) return ret; } -int power_supply_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env) { struct power_supply *psy = dev_get_drvdata(dev); - int i = 0, length = 0, ret = 0, j; + int ret = 0, j; char *prop_buf; char *attrname; @@ -212,8 +211,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "POWER_SUPPLY_NAME=%s", psy->name); + ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name); if (ret) return ret; @@ -243,9 +241,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "POWER_SUPPLY_%s=%s", - attrname, prop_buf); + ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); kfree(attrname); if (ret) goto out; @@ -282,14 +278,11 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "POWER_SUPPLY_%s=%s", - attrname, prop_buf); + ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); kfree(attrname); if (ret) goto out; } - envp[i] = NULL; out: free_page((unsigned long)prop_buf); diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index b0a18f5..5d967c4 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -44,8 +44,7 @@ ccwgroup_bus_match (struct device * dev, struct device_driver * drv) return 0; } static int -ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer, - int buffer_size) +ccwgroup_uevent (struct device *dev, struct kobj_uevent_env *env) { /* TODO */ return 0; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e44d92e..606bb53 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -78,49 +78,38 @@ static int snprint_alias(char *buf, size_t size, /* Set up environment variables for ccw device uevent. Return 0 on success, * non-zero otherwise. */ -static int ccw_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device_id *id = &(cdev->id); - int i = 0; - int len = 0; int ret; char modalias_buf[30]; /* CU_TYPE= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "CU_TYPE=%04X", id->cu_type); + ret = add_uevent_var(env, "CU_TYPE=%04X", id->cu_type); if (ret) return ret; /* CU_MODEL= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "CU_MODEL=%02X", id->cu_model); + ret = add_uevent_var(env, "CU_MODEL=%02X", id->cu_model); if (ret) return ret; /* The next two can be zero, that's ok for us */ /* DEV_TYPE= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "DEV_TYPE=%04X", id->dev_type); + ret = add_uevent_var(env, "DEV_TYPE=%04X", id->dev_type); if (ret) return ret; /* DEV_MODEL= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "DEV_MODEL=%02X", id->dev_model); + ret = add_uevent_var(env, "DEV_MODEL=%02X", id->dev_model); if (ret) return ret; /* MODALIAS= */ snprint_alias(modalias_buf, sizeof(modalias_buf), id, ""); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "MODALIAS=%s", modalias_buf); - if (ret) - return ret; - envp[i] = NULL; - return 0; + ret = add_uevent_var(env, "MODALIAS=%s", modalias_buf); + return ret; } struct bus_type ccw_bus_type; diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 90bd220..e997130 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -458,28 +458,22 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv) * uevent function for AP devices. It sets up a single environment * variable DEV_TYPE which contains the hardware device type. */ -static int ap_uevent (struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ap_uevent (struct device *dev, struct kobj_uevent_env *env) { struct ap_device *ap_dev = to_ap_dev(dev); - int retval = 0, length = 0, i = 0; + int retval = 0; if (!ap_dev) return -ENODEV; /* Set up DEV_TYPE environment variable. */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEV_TYPE=%04X", ap_dev->device_type); + retval = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type); if (retval) return retval; /* Add MODALIAS= */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=ap:t%02X", ap_dev->device_type); + retval = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type); - envp[i] = NULL; return retval; } diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 34cdce6..ede9986 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -277,16 +277,11 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv) return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0; } -static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct scsi_device *sdev = to_scsi_device(dev); - int i = 0; - int length = 0; - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type); - envp[i] = NULL; + add_uevent_var(env, "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type); return 0; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index e84d215..bcb8dd5 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -67,14 +67,11 @@ static int spi_match_device(struct device *dev, struct device_driver *drv) return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0; } -static int spi_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int spi_uevent(struct device *dev, struct kobj_uevent_env *env) { const struct spi_device *spi = to_spi_device(dev); - envp[0] = buffer; - snprintf(buffer, buffer_size, "MODALIAS=%s", spi->modalias); - envp[1] = NULL; + add_uevent_var(env, "MODALIAS=%s", spi->modalias); return 0; } diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 63b1243..6273a51 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -576,12 +576,9 @@ static int usb_device_match(struct device *dev, struct device_driver *drv) } #ifdef CONFIG_HOTPLUG -static int usb_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) { struct usb_device *usb_dev; - int i = 0; - int length = 0; if (!dev) return -ENODEV; @@ -610,51 +607,39 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp, * all the device descriptors we don't tell them about. Or * act as usermode drivers. */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE=/proc/bus/usb/%03d/%03d", + if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d", usb_dev->bus->busnum, usb_dev->devnum)) return -ENOMEM; #endif /* per-device configurations are common */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PRODUCT=%x/%x/%x", + if (add_uevent_var(env, "PRODUCT=%x/%x/%x", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice))) return -ENOMEM; /* class-based driver binding models */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "TYPE=%d/%d/%d", + if (add_uevent_var(env, "TYPE=%d/%d/%d", usb_dev->descriptor.bDeviceClass, usb_dev->descriptor.bDeviceSubClass, usb_dev->descriptor.bDeviceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "BUSNUM=%03d", + if (add_uevent_var(env, "BUSNUM=%03d", usb_dev->bus->busnum)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVNUM=%03d", + if (add_uevent_var(env, "DEVNUM=%03d", usb_dev->devnum)) return -ENOMEM; - envp[i] = NULL; return 0; } #else -static int usb_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index d8f7b08..95a49d8 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1339,14 +1339,11 @@ void usb_release_interface(struct device *dev) } #ifdef CONFIG_HOTPLUG -static int usb_if_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) { struct usb_device *usb_dev; struct usb_interface *intf; struct usb_host_interface *alt; - int i = 0; - int length = 0; if (!dev) return -ENODEV; @@ -1359,39 +1356,30 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp, alt = intf->cur_altsetting; #ifdef CONFIG_USB_DEVICEFS - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE=/proc/bus/usb/%03d/%03d", + if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d", usb_dev->bus->busnum, usb_dev->devnum)) return -ENOMEM; #endif - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PRODUCT=%x/%x/%x", + if (add_uevent_var(env, "PRODUCT=%x/%x/%x", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice))) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "TYPE=%d/%d/%d", + if (add_uevent_var(env, "TYPE=%d/%d/%d", usb_dev->descriptor.bDeviceClass, usb_dev->descriptor.bDeviceSubClass, usb_dev->descriptor.bDeviceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "INTERFACE=%d/%d/%d", + if (add_uevent_var(env, "INTERFACE=%d/%d/%d", alt->desc.bInterfaceClass, alt->desc.bInterfaceSubClass, alt->desc.bInterfaceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, + if (add_uevent_var(env, "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), @@ -1404,14 +1392,12 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp, alt->desc.bInterfaceProtocol)) return -ENOMEM; - envp[i] = NULL; return 0; } #else -static int usb_if_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index a593f90..0702173 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -197,7 +197,7 @@ static struct w1_family w1_default_family = { .fops = &w1_default_fops, }; -static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); +static int w1_uevent(struct device *dev, struct kobj_uevent_env *env); static struct bus_type w1_bus_type = { .name = "w1", @@ -396,13 +396,12 @@ static void w1_destroy_master_attributes(struct w1_master *master) } #ifdef CONFIG_HOTPLUG -static int w1_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) { struct w1_master *md = NULL; struct w1_slave *sl = NULL; char *event_owner, *name; - int err, cur_index=0, cur_len=0; + int err; if (dev->driver == &w1_master_driver) { md = container_of(dev, struct w1_master, dev); @@ -423,23 +422,19 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp, if (dev->driver != &w1_slave_driver || !sl) return 0; - err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, - &cur_len, "W1_FID=%02X", sl->reg_num.family); + err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family); if (err) return err; - err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, - &cur_len, "W1_SLAVE_ID=%024LX", - (unsigned long long)sl->reg_num.id); - envp[cur_index] = NULL; + err = add_uevent_var(env, "W1_SLAVE_ID=%024LX", + (unsigned long long)sl->reg_num.id); if (err) return err; return 0; }; #else -static int w1_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) { return 0; } diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h index ec2a8a2..93262f2 100644 --- a/include/asm-powerpc/of_device.h +++ b/include/asm-powerpc/of_device.h @@ -20,7 +20,7 @@ struct of_device extern ssize_t of_device_get_modalias(struct of_device *ofdev, char *str, ssize_t len); extern int of_device_uevent(struct device *dev, - char **envp, int num_envp, char *buffer, int buffer_size); + struct kobj_uevent_env *env); /* This is just here during the transition */ #include diff --git a/include/linux/device.h b/include/linux/device.h index 5d97ca6..2e15822 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -66,8 +66,7 @@ struct bus_type { struct driver_attribute * drv_attrs; int (*match)(struct device * dev, struct device_driver * drv); - int (*uevent)(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size); + int (*uevent)(struct device *dev, struct kobj_uevent_env *env); int (*probe)(struct device * dev); int (*remove)(struct device * dev); void (*shutdown)(struct device * dev); @@ -187,10 +186,8 @@ struct class { struct class_device_attribute * class_dev_attrs; struct device_attribute * dev_attrs; - int (*uevent)(struct class_device *dev, char **envp, - int num_envp, char *buffer, int buffer_size); - int (*dev_uevent)(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); + int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env); + int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); void (*release)(struct class_device *dev); void (*class_release)(struct class *class); @@ -266,8 +263,7 @@ struct class_device { struct attribute_group ** groups; /* optional groups */ void (*release)(struct class_device *dev); - int (*uevent)(struct class_device *dev, char **envp, - int num_envp, char *buffer, int buffer_size); + int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env); char class_id[BUS_ID_SIZE]; /* unique to this class */ }; @@ -335,8 +331,7 @@ extern void class_device_destroy(struct class *cls, dev_t devt); struct device_type { const char *name; struct attribute_group **groups; - int (*uevent)(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); + int (*uevent)(struct device *dev, struct kobj_uevent_env *env); void (*release)(struct device *dev); int (*suspend)(struct device * dev, pm_message_t state); int (*resume)(struct device * dev); diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 949706c..626bdd3 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -29,6 +29,8 @@ #define KOBJ_NAME_LEN 20 #define UEVENT_HELPER_PATH_LEN 256 +#define UEVENT_NUM_ENVP 32 /* number of env pointers */ +#define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */ /* path to the userspace helper executed on an event */ extern char uevent_helper[]; @@ -111,11 +113,18 @@ struct kobj_type { struct attribute ** default_attrs; }; +struct kobj_uevent_env { + char *envp[UEVENT_NUM_ENVP]; + int envp_idx; + char buf[UEVENT_BUFFER_SIZE]; + int buflen; +}; + struct kset_uevent_ops { int (*filter)(struct kset *kset, struct kobject *kobj); const char *(*name)(struct kset *kset, struct kobject *kobj); - int (*uevent)(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size); + int (*uevent)(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env); }; /* @@ -275,10 +284,8 @@ int kobject_uevent(struct kobject *kobj, enum kobject_action action); int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp[]); -int add_uevent_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, - const char *format, ...) - __attribute__((format (printf, 7, 8))); +int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) + __attribute__((format (printf, 2, 3))); #else static inline int kobject_uevent(struct kobject *kobj, enum kobject_action action) { return 0; } @@ -287,9 +294,7 @@ static inline int kobject_uevent_env(struct kobject *kobj, char *envp[]) { return 0; } -static inline int add_uevent_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, - const char *format, ...) +static inline int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) { return 0; } #endif diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index e06a8dc..7d8aeb3 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -22,8 +22,6 @@ #include #include -#define BUFFER_SIZE 2048 /* buffer for the variables */ -#define NUM_ENVP 32 /* number of env pointers */ /* the strings here must match the enum in include/linux/kobject.h */ const char *kobject_actions[] = { @@ -54,31 +52,21 @@ static struct sock *uevent_sock; * corresponding error when it fails. */ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, - char *envp_ext[]) + char *envp_ext[]) { - char **envp; - char *buffer; - char *scratch; - const char *action_string; + struct kobj_uevent_env *env; + const char *action_string = kobject_actions[action]; const char *devpath = NULL; const char *subsystem; struct kobject *top_kobj; struct kset *kset; struct kset_uevent_ops *uevent_ops; u64 seq; - char *seq_buff; int i = 0; int retval = 0; - int j; pr_debug("%s\n", __FUNCTION__); - action_string = kobject_actions[action]; - if (!action_string) { - pr_debug("kobject attempted to send uevent without action_string!\n"); - return -EINVAL; - } - /* search the kset we belong to */ top_kobj = kobj; while (!top_kobj->kset && top_kobj->parent) { @@ -92,7 +80,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, kset = top_kobj->kset; uevent_ops = kset->uevent_ops; - /* skip the event, if the filter returns zero. */ + /* skip the event, if the filter returns zero. */ if (uevent_ops && uevent_ops->filter) if (!uevent_ops->filter(kset, kobj)) { pr_debug("kobject filter function caused the event to drop!\n"); @@ -109,18 +97,11 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, return 0; } - /* environment index */ - envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL); - if (!envp) + /* environment buffer */ + env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); + if (!env) return -ENOMEM; - /* environment values */ - buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); - if (!buffer) { - retval = -ENOMEM; - goto exit; - } - /* complete object path */ devpath = kobject_get_path(kobj, GFP_KERNEL); if (!devpath) { @@ -128,29 +109,29 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, goto exit; } - /* event environemnt for helper process only */ - envp[i++] = "HOME=/"; - envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; - /* default keys */ - scratch = buffer; - envp [i++] = scratch; - scratch += sprintf(scratch, "ACTION=%s", action_string) + 1; - envp [i++] = scratch; - scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1; - envp [i++] = scratch; - scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1; - for (j = 0; envp_ext && envp_ext[j]; j++) - envp[i++] = envp_ext[j]; - /* just reserve the space, overwrite it after kset call has returned */ - envp[i++] = seq_buff = scratch; - scratch += strlen("SEQNUM=18446744073709551616") + 1; + retval = add_uevent_var(env, "ACTION=%s", action_string); + if (retval) + goto exit; + retval = add_uevent_var(env, "DEVPATH=%s", devpath); + if (retval) + goto exit; + retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem); + if (retval) + goto exit; + + /* keys passed in from the caller */ + if (envp_ext) { + for (i = 0; envp_ext[i]; i++) { + retval = add_uevent_var(env, envp_ext[i]); + if (retval) + goto exit; + } + } /* let the kset specific function add its stuff */ if (uevent_ops && uevent_ops->uevent) { - retval = uevent_ops->uevent(kset, kobj, - &envp[i], NUM_ENVP - i, scratch, - BUFFER_SIZE - (scratch - buffer)); + retval = uevent_ops->uevent(kset, kobj, env); if (retval) { pr_debug ("%s - uevent() returned %d\n", __FUNCTION__, retval); @@ -158,11 +139,13 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, } } - /* we will send an event, request a new sequence number */ + /* we will send an event, so request a new sequence number */ spin_lock(&sequence_lock); seq = ++uevent_seqnum; spin_unlock(&sequence_lock); - sprintf(seq_buff, "SEQNUM=%llu", (unsigned long long)seq); + retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq); + if (retval) + goto exit; #if defined(CONFIG_NET) /* send netlink message */ @@ -172,17 +155,19 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, /* allocate message with the maximum possible size */ len = strlen(action_string) + strlen(devpath) + 2; - skb = alloc_skb(len + BUFFER_SIZE, GFP_KERNEL); + skb = alloc_skb(len + env->buflen, GFP_KERNEL); if (skb) { + char *scratch; + /* add header */ scratch = skb_put(skb, len); sprintf(scratch, "%s@%s", action_string, devpath); /* copy keys to our continuous event payload buffer */ - for (i = 2; envp[i]; i++) { - len = strlen(envp[i]) + 1; + for (i = 0; i < env->envp_idx; i++) { + len = strlen(env->envp[i]) + 1; scratch = skb_put(skb, len); - strcpy(scratch, envp[i]); + strcpy(scratch, env->envp[i]); } NETLINK_CB(skb).dst_group = 1; @@ -198,13 +183,19 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, argv [0] = uevent_helper; argv [1] = (char *)subsystem; argv [2] = NULL; - call_usermodehelper (argv[0], argv, envp, UMH_WAIT_EXEC); + retval = add_uevent_var(env, "HOME=/"); + if (retval) + goto exit; + retval = add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin"); + if (retval) + goto exit; + + call_usermodehelper (argv[0], argv, env->envp, UMH_WAIT_EXEC); } exit: kfree(devpath); - kfree(buffer); - kfree(envp); + kfree(env); return retval; } @@ -227,52 +218,38 @@ int kobject_uevent(struct kobject *kobj, enum kobject_action action) EXPORT_SYMBOL_GPL(kobject_uevent); /** - * add_uevent_var - helper for creating event variables - * @envp: Pointer to table of environment variables, as passed into - * uevent() method. - * @num_envp: Number of environment variable slots available, as - * passed into uevent() method. - * @cur_index: Pointer to current index into @envp. It should be - * initialized to 0 before the first call to add_uevent_var(), - * and will be incremented on success. - * @buffer: Pointer to buffer for environment variables, as passed - * into uevent() method. - * @buffer_size: Length of @buffer, as passed into uevent() method. - * @cur_len: Pointer to current length of space used in @buffer. - * Should be initialized to 0 before the first call to - * add_uevent_var(), and will be incremented on success. - * @format: Format for creating environment variable (of the form - * "XXX=%x") for snprintf(). + * add_uevent_var - add key value string to the environment buffer + * @env: environment buffer structure + * @format: printf format for the key=value pair * * Returns 0 if environment variable was added successfully or -ENOMEM * if no space was available. */ -int add_uevent_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, - const char *format, ...) +int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) { va_list args; + int len; - /* - * We check against num_envp - 1 to make sure there is at - * least one slot left after we return, since kobject_uevent() - * needs to set the last slot to NULL. - */ - if (*cur_index >= num_envp - 1) + if (env->envp_idx >= ARRAY_SIZE(env->envp)) { + printk(KERN_ERR "add_uevent_var: too many keys\n"); + WARN_ON(1); return -ENOMEM; - - envp[*cur_index] = buffer + *cur_len; + } va_start(args, format); - *cur_len += vsnprintf(envp[*cur_index], - max(buffer_size - *cur_len, 0), - format, args) + 1; + len = vsnprintf(&env->buf[env->buflen], + sizeof(env->buf) - env->buflen, + format, args); va_end(args); - if (*cur_len > buffer_size) + if (len >= (sizeof(env->buf) - env->buflen)) { + printk(KERN_ERR "add_uevent_var: buffer size too small\n"); + WARN_ON(1); return -ENOMEM; + } - (*cur_index)++; + env->envp[env->envp_idx++] = &env->buf[env->buflen]; + env->buflen += len + 1; return 0; } EXPORT_SYMBOL_GPL(add_uevent_var); diff --git a/net/atm/atm_sysfs.c b/net/atm/atm_sysfs.c index f094a08..9ef07ed 100644 --- a/net/atm/atm_sysfs.c +++ b/net/atm/atm_sysfs.c @@ -105,10 +105,9 @@ static struct class_device_attribute *atm_attrs[] = { NULL }; -static int atm_uevent(struct class_device *cdev, char **envp, int num_envp, char *buf, int size) +static int atm_uevent(struct class_device *cdev, struct kobj_uevent_env *env) { struct atm_dev *adev; - int i = 0, len = 0; if (!cdev) return -ENODEV; @@ -117,11 +116,9 @@ static int atm_uevent(struct class_device *cdev, char **envp, int num_envp, char if (!adev) return -ENODEV; - if (add_uevent_var(envp, num_envp, &i, buf, size, &len, - "NAME=%s%d", adev->type, adev->number)) + if (add_uevent_var(env, "NAME=%s%d", adev->type, adev->number)) return -ENOMEM; - envp[i] = NULL; return 0; } diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 909a03d..6628e45 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -396,28 +396,22 @@ static struct attribute_group wireless_group = { #endif /* CONFIG_SYSFS */ #ifdef CONFIG_HOTPLUG -static int netdev_uevent(struct device *d, char **envp, - int num_envp, char *buf, int size) +static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) { struct net_device *dev = to_net_dev(d); - int retval, len = 0, i = 0; + int retval; /* pass interface to uevent. */ - retval = add_uevent_var(envp, num_envp, &i, - buf, size, &len, - "INTERFACE=%s", dev->name); + retval = add_uevent_var(env, "INTERFACE=%s", dev->name); if (retval) goto exit; /* pass ifindex to uevent. * ifindex is useful as it won't change (interface name may change) * and is what RtNetlink uses natively. */ - retval = add_uevent_var(envp, num_envp, &i, - buf, size, &len, - "IFINDEX=%d", dev->ifindex); + retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex); exit: - envp[i] = NULL; return retval; } #endif diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 2d5d225..29f820e 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -53,8 +53,7 @@ static void wiphy_dev_release(struct device *dev) } #ifdef CONFIG_HOTPLUG -static int wiphy_uevent(struct device *dev, char **envp, - int num_envp, char *buf, int size) +static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env) { /* TODO, we probably need stuff here */ return 0; diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c index 64d1639..f84f3e5 100644 --- a/sound/aoa/soundbus/core.c +++ b/sound/aoa/soundbus/core.c @@ -56,13 +56,12 @@ static int soundbus_probe(struct device *dev) } -static int soundbus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct soundbus_dev * soundbus_dev; struct of_device * of; const char *compat; - int retval = 0, i = 0, length = 0; + int retval = 0; int cplen, seen = 0; if (!dev) @@ -75,15 +74,11 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp, of = &soundbus_dev->ofdev; /* stuff we want to pass to /sbin/hotplug */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_NAME=%s", of->node->name); + retval = add_uevent_var(env, "OF_NAME=%s", of->node->name); if (retval) return retval; - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_TYPE=%s", of->node->type); + retval = add_uevent_var(env, "OF_TYPE=%s", of->node->type); if (retval) return retval; @@ -93,27 +88,19 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp, compat = of_get_property(of->node, "compatible", &cplen); while (compat && cplen > 0) { - int tmp = length; - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_%d=%s", seen, compat); + int tmp = env->buflen; + retval = add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat); if (retval) return retval; - compat += length - tmp; - cplen -= length - tmp; + compat += env->buflen - tmp; + cplen -= env->buflen - tmp; seen += 1; } - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_N=%d", seen); + retval = add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen); if (retval) return retval; - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=%s", soundbus_dev->modalias); - - envp[i] = NULL; + retval = add_uevent_var(env, "MODALIAS=%s", soundbus_dev->modalias); return retval; } -- cgit v0.10.2 From 6a8d8abb6e4497ae4132a9b1f0a956ea501f1c46 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 15 Aug 2007 15:38:28 +0200 Subject: Driver core: add CONFIG_UEVENT_HELPER_PATH The kernel creates a process for every event that is send, even when there is no binary it could execute. We are needlessly creating around 200-300 failing processes during early bootup, until we have the chance to disable it from userspace. This change allows us to disable /sbin/hotplug entirely, if you want to, by setting UEVENT_HELPER_PATH="" in the kernel config. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 5d6312e..d7da109 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -1,5 +1,13 @@ menu "Generic Driver Options" +config UEVENT_HELPER_PATH + string "path to uevent helper" + depends on HOTPLUG + default "/sbin/hotplug" + help + Path to uevent helper program forked by the kernel for + every uevent. + config STANDALONE bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL default y diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 7d8aeb3..5ccda46 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -35,7 +35,7 @@ const char *kobject_actions[] = { #if defined(CONFIG_HOTPLUG) u64 uevent_seqnum; -char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug"; +char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; static DEFINE_SPINLOCK(sequence_lock); #if defined(CONFIG_NET) static struct sock *uevent_sock; -- cgit v0.10.2 From d6b05b84edf590ff872de6310ec20d60b5b37dd2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: Driver core: remove subsys_set_kset This macro is only used by the driver core and is held over from when we had subsystems. It is not needed anymore. Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/bus.c b/drivers/base/bus.c index ff850d1..625f7e6 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -823,7 +823,8 @@ int bus_register(struct bus_type * bus) if (retval) goto out; - subsys_set_kset(bus, bus_subsys); + bus->subsys.kobj.kset = &bus_subsys; + retval = subsystem_register(&bus->subsys); if (retval) goto out; diff --git a/drivers/base/class.c b/drivers/base/class.c index ecd6336..cf9cf66 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -149,7 +149,7 @@ int class_register(struct class * cls) if (error) return error; - subsys_set_kset(cls, class_subsys); + cls->subsys.kobj.kset = &class_subsys; error = subsystem_register(&cls->subsys); if (!error) { diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 626bdd3..0713799 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -241,19 +241,6 @@ extern struct kset hypervisor_subsys; #define kset_set_kset_s(obj,subsys) \ (obj)->kset.kobj.kset = &(subsys) -/** - * subsys_set_kset(obj,subsys) - set kset for subsystem - * @obj: ptr to some object type. - * @_subsys: a subsystem object (not a ptr). - * - * Can be used for any object type with an embedded ->subsys. - * Sets the kset of @obj's kobject to @subsys.kset. This makes - * the object a member of that kset. - */ - -#define subsys_set_kset(obj,_subsys) \ - (obj)->subsys.kobj.kset = &(_subsys) - extern void subsystem_init(struct kset *); extern int __must_check subsystem_register(struct kset *); extern void subsystem_unregister(struct kset *); -- cgit v0.10.2 From 27f20e5e4e60a7f28010eeb34399fe0cc9a1a235 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: Driver core: remove kset_set_kset_s This macro is only used by the driver core and is held over from when we had subsystems. It is not needed anymore. Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 18febe2..7ad8931 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -139,7 +139,7 @@ int sysdev_class_register(struct sysdev_class * cls) kobject_name(&cls->kset.kobj)); INIT_LIST_HEAD(&cls->drivers); cls->kset.kobj.parent = &system_subsys.kobj; - kset_set_kset_s(cls, system_subsys); + cls->kset.kobj.kset = &system_subsys; return kset_register(&cls->kset); } diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 0713799..ee61ef2 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -227,20 +227,6 @@ extern struct kset hypervisor_subsys; #define kobj_set_kset_s(obj,subsys) \ (obj)->kobj.kset = &(subsys) -/** - * kset_set_kset_s(obj,subsys) - set kset for embedded kset. - * @obj: ptr to some object type. - * @subsys: a subsystem object (not a ptr). - * - * Can be used for any object type with an embedded ->kset. - * Sets the kset of @obj's embedded kobject (via its embedded - * kset) to @subsys.kset. This makes @obj a member of that - * kset. - */ - -#define kset_set_kset_s(obj,subsys) \ - (obj)->kset.kobj.kset = &(subsys) - extern void subsystem_init(struct kset *); extern int __must_check subsystem_register(struct kset *); extern void subsystem_unregister(struct kset *); -- cgit v0.10.2 From 6e9d930d167f8957a12a80515f3c417a98296378 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: Driver core: remove subsys_put() There are no more subsystems, it's a kset now so remove the function and the only two users, which are in the driver core. Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 625f7e6..2f77593 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -734,7 +734,7 @@ struct bus_type *get_bus(struct bus_type *bus) void put_bus(struct bus_type * bus) { - subsys_put(&bus->subsys); + kset_put(&bus->subsys); } diff --git a/drivers/base/class.c b/drivers/base/class.c index cf9cf66..50e3413 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -100,7 +100,7 @@ static struct class *class_get(struct class *cls) static void class_put(struct class * cls) { if (cls) - subsys_put(&cls->subsys); + kset_put(&cls->subsys); } diff --git a/include/linux/kobject.h b/include/linux/kobject.h index ee61ef2..45effed 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -238,11 +238,6 @@ static inline struct kset *subsys_get(struct kset *s) return NULL; } -static inline void subsys_put(struct kset *s) -{ - kset_put(s); -} - struct subsys_attribute { struct attribute attr; ssize_t (*show)(struct kset *, char *); diff --git a/lib/kobject.c b/lib/kobject.c index 4b08e0f..0aa4e90 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -681,7 +681,7 @@ int subsys_create_file(struct kset *s, struct subsys_attribute *a) if (subsys_get(s)) { error = sysfs_create_file(&s->kobj, &a->attr); - subsys_put(s); + kset_put(s); } return error; } -- cgit v0.10.2 From 1ef4cfac01fb5e98900f5bdb2a722aac1daff11b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: Driver core: remove subsys_get() There are no more subsystems, it's a kset now so remove the function and the only two users, which are in the driver core. Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 2f77593..bc38085 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -728,7 +728,7 @@ EXPORT_SYMBOL_GPL(device_reprobe); struct bus_type *get_bus(struct bus_type *bus) { - return bus ? container_of(subsys_get(&bus->subsys), + return bus ? container_of(kset_get(&bus->subsys), struct bus_type, subsys) : NULL; } diff --git a/drivers/base/class.c b/drivers/base/class.c index 50e3413..3e9b04c 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -93,7 +93,7 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr) static struct class *class_get(struct class *cls) { if (cls) - return container_of(subsys_get(&cls->subsys), struct class, subsys); + return container_of(kset_get(&cls->subsys), struct class, subsys); return NULL; } diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 45effed..c0fb535 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -231,13 +231,6 @@ extern void subsystem_init(struct kset *); extern int __must_check subsystem_register(struct kset *); extern void subsystem_unregister(struct kset *); -static inline struct kset *subsys_get(struct kset *s) -{ - if (s) - return kset_get(s); - return NULL; -} - struct subsys_attribute { struct attribute attr; ssize_t (*show)(struct kset *, char *); diff --git a/lib/kobject.c b/lib/kobject.c index 0aa4e90..1326041 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -679,7 +679,7 @@ int subsys_create_file(struct kset *s, struct subsys_attribute *a) if (!s || !a) return -EINVAL; - if (subsys_get(s)) { + if (kset_get(s)) { error = sysfs_create_file(&s->kobj, &a->attr); kset_put(s); } -- cgit v0.10.2 From fc1ede5888ab8a9b3e7f8567b945beed35222885 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 Sep 2007 02:53:13 -0700 Subject: Driver core: remove put_bus() put_bus() should not be globally visable as it is not used by anything other than drivers/base/bus.c. This patch removes the visability of it, and renames it to match all of the other *_put() functions in the kernel. Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/base.h b/drivers/base/base.h index 47eb02d..cebc7e7 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -19,7 +19,6 @@ extern int bus_add_device(struct device * dev); extern void bus_attach_device(struct device * dev); extern void bus_remove_device(struct device * dev); extern struct bus_type *get_bus(struct bus_type * bus); -extern void put_bus(struct bus_type * bus); extern int bus_add_driver(struct device_driver *); extern void bus_remove_driver(struct device_driver *); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index bc38085..4f53b75 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -30,6 +30,11 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, void *data); +static void bus_put(struct bus_type *bus) +{ + kset_put(&bus->subsys); +} + static ssize_t drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) { @@ -124,7 +129,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) int error; if (get_bus(bus)) { error = sysfs_create_file(&bus->subsys.kobj, &attr->attr); - put_bus(bus); + bus_put(bus); } else error = -EINVAL; return error; @@ -134,7 +139,7 @@ void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) { if (get_bus(bus)) { sysfs_remove_file(&bus->subsys.kobj, &attr->attr); - put_bus(bus); + bus_put(bus); } } @@ -186,7 +191,7 @@ static ssize_t driver_unbind(struct device_driver *drv, err = count; } put_device(dev); - put_bus(bus); + bus_put(bus); return err; } static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); @@ -219,7 +224,7 @@ static ssize_t driver_bind(struct device_driver *drv, err = -ENODEV; } put_device(dev); - put_bus(bus); + bus_put(bus); return err; } static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); @@ -459,7 +464,7 @@ out_subsys: out_id: device_remove_attrs(bus, dev); out_put: - put_bus(dev->bus); + bus_put(dev->bus); return error; } @@ -509,7 +514,7 @@ void bus_remove_device(struct device * dev) } pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); device_release_driver(dev); - put_bus(dev->bus); + bus_put(dev->bus); } } @@ -646,7 +651,7 @@ int bus_add_driver(struct device_driver *drv) out_unregister: kobject_unregister(&drv->kobj); out_put_bus: - put_bus(bus); + bus_put(bus); return error; } @@ -671,7 +676,7 @@ void bus_remove_driver(struct device_driver * drv) driver_detach(drv); module_remove_driver(drv); kobject_unregister(&drv->kobj); - put_bus(drv->bus); + bus_put(drv->bus); } @@ -732,12 +737,6 @@ struct bus_type *get_bus(struct bus_type *bus) struct bus_type, subsys) : NULL; } -void put_bus(struct bus_type * bus) -{ - kset_put(&bus->subsys); -} - - /** * find_bus - locate bus by name. * @name: name of bus. @@ -874,7 +873,7 @@ out: * @bus: bus. * * Unregister the child subsystems and the bus itself. - * Finally, we call put_bus() to release the refcount + * Finally, we call bus_put() to release the refcount */ void bus_unregister(struct bus_type * bus) { -- cgit v0.10.2 From 5901d0145c6b9e791bacd049eea11c9db9a3006e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 Sep 2007 02:53:13 -0700 Subject: Driver core: remove get_bus() get_bus() should not be globally visable as it is not used by anything other than drivers/base/bus.c. This patch removes the visability of it, and renames it to match all of the other *_get() functions in the kernel. Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/base.h b/drivers/base/base.h index cebc7e7..10b2fb6 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -18,7 +18,6 @@ extern int attribute_container_init(void); extern int bus_add_device(struct device * dev); extern void bus_attach_device(struct device * dev); extern void bus_remove_device(struct device * dev); -extern struct bus_type *get_bus(struct bus_type * bus); extern int bus_add_driver(struct device_driver *); extern void bus_remove_driver(struct device_driver *); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 4f53b75..0a8d075 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -30,6 +30,12 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, void *data); +static struct bus_type *bus_get(struct bus_type *bus) +{ + return bus ? container_of(kset_get(&bus->subsys), + struct bus_type, subsys) : NULL; +} + static void bus_put(struct bus_type *bus) { kset_put(&bus->subsys); @@ -127,7 +133,7 @@ static struct sysfs_ops bus_sysfs_ops = { int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) { int error; - if (get_bus(bus)) { + if (bus_get(bus)) { error = sysfs_create_file(&bus->subsys.kobj, &attr->attr); bus_put(bus); } else @@ -137,7 +143,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) { - if (get_bus(bus)) { + if (bus_get(bus)) { sysfs_remove_file(&bus->subsys.kobj, &attr->attr); bus_put(bus); } @@ -177,7 +183,7 @@ static int driver_helper(struct device *dev, void *data) static ssize_t driver_unbind(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = get_bus(drv->bus); + struct bus_type *bus = bus_get(drv->bus); struct device *dev; int err = -ENODEV; @@ -204,7 +210,7 @@ static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); static ssize_t driver_bind(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = get_bus(drv->bus); + struct bus_type *bus = bus_get(drv->bus); struct device *dev; int err = -ENODEV; @@ -435,7 +441,7 @@ static inline void remove_deprecated_bus_links(struct device *dev) { } */ int bus_add_device(struct device * dev) { - struct bus_type * bus = get_bus(dev->bus); + struct bus_type * bus = bus_get(dev->bus); int error = 0; if (bus) { @@ -611,7 +617,7 @@ static inline void remove_probe_files(struct bus_type *bus) {} */ int bus_add_driver(struct device_driver *drv) { - struct bus_type * bus = get_bus(drv->bus); + struct bus_type * bus = bus_get(drv->bus); int error = 0; if (!bus) @@ -731,12 +737,6 @@ int device_reprobe(struct device *dev) } EXPORT_SYMBOL_GPL(device_reprobe); -struct bus_type *get_bus(struct bus_type *bus) -{ - return bus ? container_of(kset_get(&bus->subsys), - struct bus_type, subsys) : NULL; -} - /** * find_bus - locate bus by name. * @name: name of bus. -- cgit v0.10.2 From 19c38de88a80913351fcacefdb461cc0b585fa87 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: kobjects: fix up improper use of the kobject name field A number of different drivers incorrect access the kobject name field directly. This is not correct as the name might not be in the array. Use the proper accessor function instead. diff --git a/block/elevator.c b/block/elevator.c index c6d153d..b9c518a 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -186,7 +186,7 @@ static elevator_t *elevator_alloc(struct request_queue *q, eq->ops = &e->ops; eq->elevator_type = e; kobject_init(&eq->kobj); - snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched"); + kobject_set_name(&eq->kobj, "%s", "iosched"); eq->kobj.ktype = &elv_ktype; mutex_init(&eq->sysfs_lock); diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index cd9d2c5..d875673 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1854,7 +1854,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) init_timer(&q->unplug_timer); - snprintf(q->kobj.name, KOBJ_NAME_LEN, "%s", "queue"); + kobject_set_name(&q->kobj, "%s", "queue"); q->kobj.ktype = &queue_ktype; kobject_init(&q->kobj); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index feab124..cbfc815 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -194,7 +194,7 @@ int acpi_bus_set_power(acpi_handle handle, int state) if (!device->flags.power_manageable) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n", - device->dev.kobj.name)); + kobject_name(&device->dev.kobj))); return -ENODEV; } /* diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2f6a73c..2ce3de5 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -828,7 +828,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) /* prepare interface data */ policy->kobj.parent = &sys_dev->kobj; policy->kobj.ktype = &ktype_cpufreq; - strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN); + kobject_set_name(&policy->kobj, "cpufreq"); ret = kobject_register(&policy->kobj); if (ret) { diff --git a/drivers/md/md.c b/drivers/md/md.c index e8f102e..acf1b81 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3076,8 +3076,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) mddev->gendisk = disk; mutex_unlock(&disks_mutex); mddev->kobj.parent = &disk->kobj; - mddev->kobj.k_name = NULL; - snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md"); + kobject_set_name(&mddev->kobj, "%s", "md"); mddev->kobj.ktype = &md_ktype; if (kobject_register(&mddev->kobj)) printk(KERN_WARNING "md: cannot register %s/md - name in use\n", diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 4ac161e..7d7758f 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1183,7 +1183,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ pool_count[i], pool_size[i], pool_active[i]); kobj->parent = &dev->dev.kobj; - sprintf(kobj->name, "pool%d", i); + kobject_set_name(kobj, "pool%d", i); kobj->ktype = &ktype_veth_pool; kobject_register(kobj); } diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c index 568f187..05ca2ed 100644 --- a/drivers/pci/setup-irq.c +++ b/drivers/pci/setup-irq.c @@ -48,7 +48,7 @@ pdev_fixup_irq(struct pci_dev *dev, dev->irq = irq; pr_debug("PCI: fixup irq: (%s) got %d\n", - dev->dev.kobj.name, dev->irq); + kobject_name(&dev->dev.kobj), dev->irq); /* Always tell the device, so the driver knows what is the real IRQ to use; the device does not use it. */ diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 783c57e..722e12e 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -381,10 +381,12 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, p->partno = part; p->policy = disk->policy; - if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1])) - snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part); + if (isdigit(disk->kobj.k_name[strlen(disk->kobj.k_name)-1])) + kobject_set_name(&p->kobj, "%sp%d", + kobject_name(&disk->kobj), part); else - snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part); + kobject_set_name(&p->kobj, "%s%d", + kobject_name(&disk->kobj),part); p->kobj.parent = &disk->kobj; p->kobj.ktype = &ktype_part; kobject_init(&p->kobj); @@ -477,9 +479,9 @@ void register_disk(struct gendisk *disk) struct hd_struct *p; int err; - strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN); + kobject_set_name(&disk->kobj, "%s", disk->disk_name); /* ewww... some of these buggers have / in name... */ - s = strchr(disk->kobj.name, '/'); + s = strchr(disk->kobj.k_name, '/'); if (s) *s = '!'; if ((err = kobject_add(&disk->kobj))) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 83e76b3..ea33b66 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -1013,7 +1013,7 @@ again: goto again; } - new_dentry = lookup_one_len(kobj->name, new_parent, strlen(kobj->name)); + new_dentry = lookup_one_len(kobject_name(kobj), new_parent, strlen(kobject_name(kobj))); if (IS_ERR(new_dentry)) { error = PTR_ERR(new_dentry); goto out_unlock; diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index c65f54e..3312e8f 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -435,7 +435,7 @@ int br_sysfs_addbr(struct net_device *dev) err = kobject_register(&br->ifobj); if (err) { pr_info("%s: can't add kobject (directory) %s/%s\n", - __FUNCTION__, dev->name, br->ifobj.name); + __FUNCTION__, dev->name, kobject_name(&br->ifobj)); goto out3; } return 0; -- cgit v0.10.2 From 7e7654a92a5a75a350cc3458389bc76273498f6a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: cdev: remove unneeded setting of cdev names struct cdev does not need the kobject name to be set, as it is never used. This patch fixes up the few places it is set. Signed-off-by: Greg Kroah-Hartman Acked-by: Mauro Carvalho Chehab diff --git a/block/bsg.c b/block/bsg.c index ed26468..b8ddfc6 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -1010,10 +1010,7 @@ unlock: } EXPORT_SYMBOL_GPL(bsg_register_queue); -static struct cdev bsg_cdev = { - .kobj = {.name = "bsg", }, - .owner = THIS_MODULE, -}; +static struct cdev bsg_cdev; static int __init bsg_init(void) { diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 1f0d7c6..bbfa0e2 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -255,10 +255,7 @@ static const struct file_operations raw_ctl_fops = { .owner = THIS_MODULE, }; -static struct cdev raw_cdev = { - .kobj = {.name = "raw", }, - .owner = THIS_MODULE, -}; +static struct cdev raw_cdev; static int __init raw_init(void) { diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 56231d8..18738fa 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -103,10 +103,7 @@ static struct file_operations dvb_device_fops = .open = dvb_device_open, }; -static struct cdev dvb_device_cdev = { - .kobj = {.name = "dvb", }, - .owner = THIS_MODULE, -}; +static struct cdev dvb_device_cdev; int dvb_generic_open(struct inode *inode, struct file *file) { diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 927a181..fe98796 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1576,6 +1576,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai } const struct file_operations usbdev_file_operations = { + .owner = THIS_MODULE, .llseek = usbdev_lseek, .read = usbdev_read, .poll = usbdev_poll, @@ -1625,10 +1626,7 @@ static struct notifier_block usbdev_nb = { }; #endif -static struct cdev usb_device_cdev = { - .kobj = {.name = "usb_device", }, - .owner = THIS_MODULE, -}; +static struct cdev usb_device_cdev; int __init usb_devio_init(void) { -- cgit v0.10.2 From 34980ca8faebfcce31094eba6ffbb0113950361f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: Drivers: clean up direct setting of the name of a kset A kset should not have its name set directly, so dynamically set the name at runtime. This is needed to remove the static array in the kobject structure which will be changed in a future patch. Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 4a0576b..3706b2b 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -743,7 +743,7 @@ static struct kobj_type ktype_mc_set_attribs = { * /sys/devices/system/edac/mc */ static struct kset mc_kset = { - .kobj = {.name = "mc", .ktype = &ktype_mc_set_attribs }, + .kobj = {.ktype = &ktype_mc_set_attribs }, .ktype = &ktype_mci, }; @@ -1010,6 +1010,7 @@ int edac_sysfs_setup_mc_kset(void) } /* Init the MC's kobject */ + kobject_set_name(&mc_kset.kobj, "mc"); mc_kset.kobj.parent = &edac_class->kset.kobj; /* register the mc_kset */ diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index df07606..a080fed 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -129,17 +129,17 @@ struct kobj_type ktype_dlpar_io = { }; struct kset dlpar_io_kset = { - .kobj = {.name = DLPAR_KOBJ_NAME, - .ktype = &ktype_dlpar_io, + .kobj = {.ktype = &ktype_dlpar_io, .parent = &pci_hotplug_slots_subsys.kobj}, .ktype = &ktype_dlpar_io, }; int dlpar_sysfs_init(void) { + kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME); if (kset_register(&dlpar_io_kset)) { printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n", - dlpar_io_kset.kobj.name); + kobject_name(&dlpar_io_kset.kobj)); return -EINVAL; } diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 1dc7210..f88f88f 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -167,7 +167,6 @@ static struct kobj_type dlm_ktype = { }; static struct kset dlm_kset = { - .kobj = {.name = "dlm",}, .ktype = &dlm_ktype, }; @@ -228,6 +227,7 @@ int dlm_lockspace_init(void) INIT_LIST_HEAD(&lslist); spin_lock_init(&lslist_lock); + kobject_set_name(&dlm_kset.kobj, "dlm"); kobj_set_kset_s(&dlm_kset, kernel_subsys); error = kset_register(&dlm_kset); if (error) diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c index d9fe3ca..ae9e6a2 100644 --- a/fs/gfs2/locking/dlm/sysfs.c +++ b/fs/gfs2/locking/dlm/sysfs.c @@ -190,7 +190,6 @@ static struct kobj_type gdlm_ktype = { }; static struct kset gdlm_kset = { - .kobj = {.name = "lock_dlm",}, .ktype = &gdlm_ktype, }; @@ -224,6 +223,7 @@ int gdlm_sysfs_init(void) { int error; + kobject_set_name(&gdlm_kset.kobj, "lock_dlm"); kobj_set_kset_s(&gdlm_kset, kernel_subsys); error = kset_register(&gdlm_kset); if (error) diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index c26c21b..640cb6a 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -222,7 +222,6 @@ static struct kobj_type gfs2_ktype = { }; static struct kset gfs2_kset = { - .kobj = {.name = "gfs2"}, .ktype = &gfs2_ktype, }; @@ -553,6 +552,7 @@ int gfs2_sys_init(void) { gfs2_sys_margs = NULL; spin_lock_init(&gfs2_sys_margs_lock); + kobject_set_name(&gfs2_kset.kobj, "gfs2"); kobj_set_kset_s(&gfs2_kset, fs_subsys); return kset_register(&gfs2_kset); } diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c index e9e042b..a4882c8 100644 --- a/fs/ocfs2/cluster/masklog.c +++ b/fs/ocfs2/cluster/masklog.c @@ -143,7 +143,7 @@ static struct kobj_type mlog_ktype = { }; static struct kset mlog_kset = { - .kobj = {.name = "logmask", .ktype = &mlog_ktype}, + .kobj = {.ktype = &mlog_ktype}, }; int mlog_sys_init(struct kset *o2cb_subsys) @@ -156,6 +156,7 @@ int mlog_sys_init(struct kset *o2cb_subsys) } mlog_attr_ptrs[i] = NULL; + kobject_set_name(&mlog_kset.kobj, "logmask"); kobj_set_kset_s(&mlog_kset, *o2cb_subsys); return kset_register(&mlog_kset); } -- cgit v0.10.2 From ce2c9cb0259acd2aed184499ebe41ab00da13b25 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: kobject: remove the static array for the name Due to historical reasons, struct kobject contained a static array for the name, and a dynamic pointer in case the name got bigger than the array. That's just dumb, as people didn't always know which variable to reference, even with the accessor for the kobject name. This patch removes the static array, potentially saving a lot of memory as the majority of kobjects do not have a very long name. Thanks to Kay for the idea to do this. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/kobject.h b/include/linux/kobject.h index c0fb535..8b45946 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -63,7 +63,6 @@ extern const char *kobject_actions[]; struct kobject { const char * k_name; - char name[KOBJ_NAME_LEN]; struct kref kref; struct list_head entry; struct kobject * parent; @@ -188,18 +187,18 @@ extern struct kobject * kset_find_obj(struct kset *, const char *); * Use this when initializing an embedded kset with no other * fields to initialize. */ -#define set_kset_name(str) .kset = { .kobj = { .name = str } } +#define set_kset_name(str) .kset = { .kobj = { .k_name = str } } #define decl_subsys(_name,_type,_uevent_ops) \ struct kset _name##_subsys = { \ - .kobj = { .name = __stringify(_name) }, \ + .kobj = { .k_name = __stringify(_name) }, \ .ktype = _type, \ .uevent_ops =_uevent_ops, \ } #define decl_subsys_name(_varname,_name,_type,_uevent_ops) \ struct kset _varname##_subsys = { \ - .kobj = { .name = __stringify(_name) }, \ + .kobj = { .k_name = __stringify(_name) }, \ .ktype = _type, \ .uevent_ops =_uevent_ops, \ } diff --git a/lib/kobject.c b/lib/kobject.c index 1326041..10ae2eb 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -170,7 +170,7 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent) if (!(kobj = kobject_get(kobj))) return -ENOENT; if (!kobj->k_name) - kobj->k_name = kobj->name; + kobject_set_name(kobj, "NO_NAME"); if (!*kobj->k_name) { pr_debug("kobject attempted to be registered with no name!\n"); WARN_ON(1); @@ -181,7 +181,7 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent) pr_debug("kobject %s: registering. parent: %s, set: %s\n", kobject_name(kobj), parent ? kobject_name(parent) : "", - kobj->kset ? kobj->kset->kobj.name : "" ); + kobj->kset ? kobject_name(&kobj->kset->kobj) : "" ); if (kobj->kset) { spin_lock(&kobj->kset->list_lock); @@ -255,54 +255,50 @@ int kobject_register(struct kobject * kobj) int kobject_set_name(struct kobject * kobj, const char * fmt, ...) { int error = 0; - int limit = KOBJ_NAME_LEN; + int limit; int need; va_list args; - char * name; + char *name; - /* - * First, try the static array - */ - va_start(args,fmt); - need = vsnprintf(kobj->name,limit,fmt,args); + /* find out how big a buffer we need */ + name = kmalloc(1024, GFP_KERNEL); + if (!name) { + error = -ENOMEM; + goto done; + } + va_start(args, fmt); + need = vsnprintf(name, 1024, fmt, args); va_end(args); - if (need < limit) - name = kobj->name; - else { - /* - * Need more space? Allocate it and try again - */ - limit = need + 1; - name = kmalloc(limit,GFP_KERNEL); - if (!name) { - error = -ENOMEM; - goto Done; - } - va_start(args,fmt); - need = vsnprintf(name,limit,fmt,args); - va_end(args); - - /* Still? Give up. */ - if (need >= limit) { - kfree(name); - error = -EFAULT; - goto Done; - } + kfree(name); + + /* Allocate the new space and copy the string in */ + limit = need + 1; + name = kmalloc(limit, GFP_KERNEL); + if (!name) { + error = -ENOMEM; + goto done; + } + va_start(args, fmt); + need = vsnprintf(name, limit, fmt, args); + va_end(args); + + /* something wrong with the string we copied? */ + if (need >= limit) { + kfree(name); + error = -EFAULT; + goto done; } /* Free the old name, if necessary. */ - if (kobj->k_name && kobj->k_name != kobj->name) - kfree(kobj->k_name); + kfree(kobj->k_name); /* Now, set the new name */ kobj->k_name = name; - Done: +done: return error; } - EXPORT_SYMBOL(kobject_set_name); - /** * kobject_rename - change the name of an object * @kobj: object in question. @@ -477,13 +473,16 @@ void kobject_cleanup(struct kobject * kobj) struct kobj_type * t = get_ktype(kobj); struct kset * s = kobj->kset; struct kobject * parent = kobj->parent; + const char *name = kobj->k_name; pr_debug("kobject %s: cleaning up\n",kobject_name(kobj)); - if (kobj->k_name != kobj->name) - kfree(kobj->k_name); - kobj->k_name = NULL; - if (t && t->release) + if (t && t->release) { t->release(kobj); + /* If we have a release function, we can guess that this was + * not a statically allocated kobject, so we should be safe to + * free the name */ + kfree(name); + } if (s) kset_put(s); kobject_put(parent); -- cgit v0.10.2 From d716551e188787effb08bf87a846404cfd239a8b Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 14 Sep 2007 13:25:19 +0200 Subject: Driver core: clean up removed functions from the documentation Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt index 8ee49ee..5e7aca2 100644 --- a/Documentation/kobject.txt +++ b/Documentation/kobject.txt @@ -54,7 +54,6 @@ embedded in larger data structures and replace fields they duplicate. struct kobject { const char * k_name; - char name[KOBJ_NAME_LEN]; struct kref kref; struct list_head entry; struct kobject * parent; @@ -223,18 +222,15 @@ decl_subsys(devices, &ktype_device, &device_uevent_ops); is equivalent to doing: struct kset devices_subsys = { - .kobj = { - .name = "devices", - }, .ktype = &ktype_devices, .uevent_ops = &device_uevent_ops, }; - +kobject_set_name(&devices_subsys, name); The objects that are registered with a subsystem that use the subsystem's default list must have their kset ptr set properly. These objects may have embedded kobjects or ksets. The -following helpers make setting the kset easier: +following helper makes setting the kset easier: kobj_set_kset_s(obj,subsys) @@ -242,22 +238,9 @@ kobj_set_kset_s(obj,subsys) - Assumes that obj->kobj exists, and is a struct kobject. - Sets the kset of that kobject to the kset . - -kset_set_kset_s(obj,subsys) - -- Assumes that obj->kset exists, and is a struct kset. -- Sets the kset of the embedded kobject to the kset . - -subsys_set_kset(obj,subsys) - -- Assumes obj->subsys exists, and is a struct subsystem. -- Sets obj->subsys.kset.kobj.kset to the subsystem's embedded kset. - void subsystem_init(struct kset *s); int subsystem_register(struct kset *s); void subsystem_unregister(struct kset *s); -struct kset *subsys_get(struct kset *s); -void kset_put(struct kset *s); These are just wrappers around the respective kset_* functions. -- cgit v0.10.2 From 2ebefc50161a0a1cdebccd62be749e72abdbec37 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Thu, 2 Aug 2007 18:23:50 -0400 Subject: debugfs: helper for decimal challenged Allows debugfs helper functions to have a hex output, rather than just decimal Signed-off-by: Robin Getz Signed-off-by: Greg Kroah-Hartman diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 2e124e0..a9b99c0 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -221,6 +221,42 @@ struct dentry *debugfs_create_u64(const char *name, mode_t mode, } EXPORT_SYMBOL_GPL(debugfs_create_u64); +DEFINE_SIMPLE_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n"); + +DEFINE_SIMPLE_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%04llx\n"); + +DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n"); + +/** + * debugfs_create_x8 - create a debugfs file that is used to read and write an unsigned 8-bit value + * debugfs_create_x16 - create a debugfs file that is used to read and write an unsigned 16-bit value + * debugfs_create_x32 - create a debugfs file that is used to read and write an unsigned 32-bit value + * + * These functions are exactly the same as the above functions, (but use a hex + * output for the decimal challenged) for details look at the above unsigned + * decimal functions. + */ +struct dentry *debugfs_create_x8(const char *name, mode_t mode, + struct dentry *parent, u8 *value) +{ + return debugfs_create_file(name, mode, parent, value, &fops_x8); +} +EXPORT_SYMBOL_GPL(debugfs_create_x8); + +struct dentry *debugfs_create_x16(const char *name, mode_t mode, + struct dentry *parent, u16 *value) +{ + return debugfs_create_file(name, mode, parent, value, &fops_x16); +} +EXPORT_SYMBOL_GPL(debugfs_create_x16); + +struct dentry *debugfs_create_x32(const char *name, mode_t mode, + struct dentry *parent, u32 *value) +{ + return debugfs_create_file(name, mode, parent, value, &fops_x32); +} +EXPORT_SYMBOL_GPL(debugfs_create_x32); + static ssize_t read_file_bool(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index 104e51e..f592d6d 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -49,6 +49,12 @@ struct dentry *debugfs_create_u32(const char *name, mode_t mode, struct dentry *parent, u32 *value); struct dentry *debugfs_create_u64(const char *name, mode_t mode, struct dentry *parent, u64 *value); +struct dentry *debugfs_create_x8(const char *name, mode_t mode, + struct dentry *parent, u8 *value); +struct dentry *debugfs_create_x16(const char *name, mode_t mode, + struct dentry *parent, u16 *value); +struct dentry *debugfs_create_x32(const char *name, mode_t mode, + struct dentry *parent, u32 *value); struct dentry *debugfs_create_bool(const char *name, mode_t mode, struct dentry *parent, u32 *value); @@ -122,6 +128,27 @@ static inline struct dentry *debugfs_create_u64(const char *name, mode_t mode, return ERR_PTR(-ENODEV); } +static inline struct dentry *debugfs_create_x8(const char *name, mode_t mode, + struct dentry *parent, + u8 *value) +{ + return ERR_PTR(-ENODEV); +} + +static inline struct dentry *debugfs_create_x16(const char *name, mode_t mode, + struct dentry *parent, + u16 *value) +{ + return ERR_PTR(-ENODEV); +} + +static inline struct dentry *debugfs_create_x32(const char *name, mode_t mode, + struct dentry *parent, + u32 *value) +{ + return ERR_PTR(-ENODEV); +} + static inline struct dentry *debugfs_create_bool(const char *name, mode_t mode, struct dentry *parent, u32 *value) -- cgit v0.10.2 From 52e8c209d6d2bae6766b9940a107c73e943583f1 Mon Sep 17 00:00:00 2001 From: Dave Young Date: Thu, 26 Jul 2007 11:03:54 +0000 Subject: sysfs/file.c - use mutex instead of semaphore Use mutex instead of semaphore in sysfs/file.c : sys_buffer. Signed-off-by: Dave Young Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 3e1cc06..b21d11b 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -8,8 +8,8 @@ #include #include #include +#include #include -#include #include "sysfs.h" @@ -55,7 +55,7 @@ struct sysfs_buffer { loff_t pos; char * page; struct sysfs_ops * ops; - struct semaphore sem; + struct mutex mutex; int needs_read_fill; int event; }; @@ -128,7 +128,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) struct sysfs_buffer * buffer = file->private_data; ssize_t retval = 0; - down(&buffer->sem); + mutex_lock(&buffer->mutex); if (buffer->needs_read_fill) { retval = fill_read_buffer(file->f_path.dentry,buffer); if (retval) @@ -139,7 +139,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) retval = simple_read_from_buffer(buf, count, ppos, buffer->page, buffer->count); out: - up(&buffer->sem); + mutex_unlock(&buffer->mutex); return retval; } @@ -228,13 +228,13 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t struct sysfs_buffer * buffer = file->private_data; ssize_t len; - down(&buffer->sem); + mutex_lock(&buffer->mutex); len = fill_write_buffer(buffer, buf, count); if (len > 0) len = flush_write_buffer(file->f_path.dentry, buffer, len); if (len > 0) *ppos += len; - up(&buffer->sem); + mutex_unlock(&buffer->mutex); return len; } @@ -294,7 +294,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) if (!buffer) goto err_out; - init_MUTEX(&buffer->sem); + mutex_init(&buffer->mutex); buffer->needs_read_fill = 1; buffer->ops = ops; file->private_data = buffer; -- cgit v0.10.2 From 869512ab5ab93e5e82ad7d4aaf4ed098d23bfc3f Mon Sep 17 00:00:00 2001 From: Dave Young Date: Thu, 26 Jul 2007 14:53:53 +0000 Subject: sysfs: cleanup semaphore.h Cleanup semaphore.h Signed-off-by: Dave Young Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 5afe2a2..a819a7e 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -14,9 +14,9 @@ #include #include #include +#include #include -#include #include "sysfs.h" diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index ea33b66..86d75e0 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include "sysfs.h" DEFINE_MUTEX(sysfs_mutex); diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index f318b73..e6b904d 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "sysfs.h" diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 10d1b52..aecb6e7 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "sysfs.h" extern struct super_block * sysfs_sb; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index fbc7b65..69a73ae 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -8,7 +8,6 @@ #include #include #include -#include #include "sysfs.h" diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 4ce687f..9048453 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "sysfs.h" -- cgit v0.10.2 From 90bc61359de0148f8627073d68a22edc7ed9893d Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 31 Jul 2007 19:15:08 +0900 Subject: sysfs: Remove first pass at shadow directory support While shadow directories appear to be a good idea, the current scheme of controlling their creation and destruction outside of sysfs appears to be a locking and maintenance nightmare in the face of sysfs directories dynamically coming and going. Which can now occur for directories containing network devices when CONFIG_SYSFS_DEPRECATED is not set. This patch removes everything from the initial shadow directory support that allowed the shadow directory creation to be controlled at a higher level. So except for a few bits of sysfs_rename_dir everything from commit b592fcfe7f06c15ec11774b5be7ce0de3aa86e73 is now gone. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 86d75e0..837073d 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -569,9 +569,6 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd) spin_unlock(&dcache_lock); spin_unlock(&sysfs_assoc_lock); - /* dentries for shadowed inodes are pinned, unpin */ - if (dentry && sysfs_is_shadowed_inode(dentry->d_inode)) - dput(dentry); dput(dentry); /* adjust nlink and update timestamp */ @@ -723,19 +720,15 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, /** * sysfs_create_dir - create a directory for an object. * @kobj: object we're creating directory for. - * @shadow_parent: parent object. */ -int sysfs_create_dir(struct kobject *kobj, - struct sysfs_dirent *shadow_parent_sd) +int sysfs_create_dir(struct kobject * kobj) { struct sysfs_dirent *parent_sd, *sd; int error = 0; BUG_ON(!kobj); - if (shadow_parent_sd) - parent_sd = shadow_parent_sd; - else if (kobj->parent) + if (kobj->parent) parent_sd = kobj->parent->sd; else if (sysfs_mount && sysfs_mount->mnt_sb) parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata; @@ -890,45 +883,44 @@ void sysfs_remove_dir(struct kobject * kobj) __sysfs_remove_dir(sd); } -int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, - const char *new_name) +int sysfs_rename_dir(struct kobject * kobj, const char *new_name) { - struct sysfs_dirent *sd = kobj->sd; - struct dentry *new_parent = NULL; + struct sysfs_dirent *sd; + struct dentry *parent = NULL; struct dentry *old_dentry = NULL, *new_dentry = NULL; + struct sysfs_dirent *parent_sd; const char *dup_name = NULL; int error; + if (!kobj->parent) + return -EINVAL; + /* get dentries */ + sd = kobj->sd; old_dentry = sysfs_get_dentry(sd); if (IS_ERR(old_dentry)) { error = PTR_ERR(old_dentry); goto out_dput; } - new_parent = sysfs_get_dentry(new_parent_sd); - if (IS_ERR(new_parent)) { - error = PTR_ERR(new_parent); + parent_sd = kobj->parent->sd; + parent = sysfs_get_dentry(parent_sd); + if (IS_ERR(parent)) { + error = PTR_ERR(parent); goto out_dput; } - /* lock new_parent and get dentry for new name */ - mutex_lock(&new_parent->d_inode->i_mutex); + /* lock parent and get dentry for new name */ + mutex_lock(&parent->d_inode->i_mutex); - new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name)); + new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); if (IS_ERR(new_dentry)) { error = PTR_ERR(new_dentry); goto out_unlock; } - /* By allowing two different directories with the same - * d_parent we allow this routine to move between different - * shadows of the same directory - */ error = -EINVAL; - if (old_dentry->d_parent->d_inode != new_parent->d_inode || - new_dentry->d_parent->d_inode != new_parent->d_inode || - old_dentry == new_dentry) + if (old_dentry == new_dentry) goto out_unlock; error = -EEXIST; @@ -955,9 +947,9 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, d_move(sd->s_dentry, new_dentry); sysfs_unlink_sibling(sd); - sysfs_get(new_parent_sd); + sysfs_get(parent_sd); sysfs_put(sd->s_parent); - sd->s_parent = new_parent_sd; + sd->s_parent = parent_sd; sysfs_link_sibling(sd); mutex_unlock(&sysfs_mutex); @@ -968,10 +960,10 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, out_drop: d_drop(new_dentry); out_unlock: - mutex_unlock(&new_parent->d_inode->i_mutex); + mutex_unlock(&parent->d_inode->i_mutex); out_dput: kfree(dup_name); - dput(new_parent); + dput(parent); dput(old_dentry); dput(new_dentry); return error; @@ -1192,121 +1184,6 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) return offset; } - -/** - * sysfs_make_shadowed_dir - Setup so a directory can be shadowed - * @kobj: object we're creating shadow of. - */ - -int sysfs_make_shadowed_dir(struct kobject *kobj, - void * (*follow_link)(struct dentry *, struct nameidata *)) -{ - struct dentry *dentry; - struct inode *inode; - struct inode_operations *i_op; - - /* get dentry for @kobj->sd, dentry of a shadowed dir is pinned */ - dentry = sysfs_get_dentry(kobj->sd); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - inode = dentry->d_inode; - if (inode->i_op != &sysfs_dir_inode_operations) { - dput(dentry); - return -EINVAL; - } - - i_op = kmalloc(sizeof(*i_op), GFP_KERNEL); - if (!i_op) - return -ENOMEM; - - memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op)); - i_op->follow_link = follow_link; - - /* Locking of inode->i_op? - * Since setting i_op is a single word write and they - * are atomic we should be ok here. - */ - inode->i_op = i_op; - return 0; -} - -/** - * sysfs_create_shadow_dir - create a shadow directory for an object. - * @kobj: object we're creating directory for. - * - * sysfs_make_shadowed_dir must already have been called on this - * directory. - */ - -struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj) -{ - struct sysfs_dirent *parent_sd = kobj->sd->s_parent; - struct dentry *dir, *parent, *shadow; - struct inode *inode; - struct sysfs_dirent *sd; - struct sysfs_addrm_cxt acxt; - - dir = sysfs_get_dentry(kobj->sd); - if (IS_ERR(dir)) { - sd = (void *)dir; - goto out; - } - parent = dir->d_parent; - - inode = dir->d_inode; - sd = ERR_PTR(-EINVAL); - if (!sysfs_is_shadowed_inode(inode)) - goto out_dput; - - shadow = d_alloc(parent, &dir->d_name); - if (!shadow) - goto nomem; - - sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR); - if (!sd) - goto nomem; - sd->s_elem.dir.kobj = kobj; - - sysfs_addrm_start(&acxt, parent_sd); - - /* add but don't link into children list */ - sysfs_add_one(&acxt, sd); - - /* attach and instantiate dentry */ - sysfs_attach_dentry(sd, shadow); - d_instantiate(shadow, igrab(inode)); - inc_nlink(inode); /* tj: synchronization? */ - - sysfs_addrm_finish(&acxt); - - dget(shadow); /* Extra count - pin the dentry in core */ - - goto out_dput; - - nomem: - dput(shadow); - sd = ERR_PTR(-ENOMEM); - out_dput: - dput(dir); - out: - return sd; -} - -/** - * sysfs_remove_shadow_dir - remove an object's directory. - * @shadow_sd: sysfs_dirent of shadow directory - * - * The only thing special about this is that we remove any files in - * the directory before we remove the directory, and we've inlined - * what used to be sysfs_rmdir() below, instead of calling separately. - */ - -void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd) -{ - __sysfs_remove_dir(shadow_sd); -} - const struct file_operations sysfs_dir_operations = { .open = sysfs_dir_open, .release = sysfs_dir_close, diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index e6b904d..d197237 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -13,7 +13,6 @@ #include #include #include -#include #include "sysfs.h" diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index aecb6e7..45128b7 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -33,16 +33,6 @@ static const struct inode_operations sysfs_inode_operations ={ .setattr = sysfs_setattr, }; -void sysfs_delete_inode(struct inode *inode) -{ - /* Free the shadowed directory inode operations */ - if (sysfs_is_shadowed_inode(inode)) { - kfree(inode->i_op); - inode->i_op = NULL; - } - return generic_delete_inode(inode); -} - int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) { struct inode * inode = dentry->d_inode; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 69a73ae..119f39d 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -20,7 +20,7 @@ struct kmem_cache *sysfs_dir_cachep; static const struct super_operations sysfs_ops = { .statfs = simple_statfs, - .drop_inode = sysfs_delete_inode, + .drop_inode = generic_delete_inode, }; struct sysfs_dirent sysfs_root = { diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 6b8c8d7..b55e510 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -70,7 +70,6 @@ extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); -extern void sysfs_delete_inode(struct inode *inode); extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd); extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode); @@ -121,8 +120,3 @@ static inline void sysfs_put(struct sysfs_dirent * sd) if (sd && atomic_dec_and_test(&sd->s_count)) release_sysfs_dirent(sd); } - -static inline int sysfs_is_shadowed_inode(struct inode *inode) -{ - return S_ISDIR(inode->i_mode) && inode->i_op->follow_link; -} diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 8b45946..56f5eaf 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -84,14 +84,9 @@ extern void kobject_init(struct kobject *); extern void kobject_cleanup(struct kobject *); extern int __must_check kobject_add(struct kobject *); -extern int __must_check kobject_shadow_add(struct kobject *kobj, - struct sysfs_dirent *shadow_parent); extern void kobject_del(struct kobject *); extern int __must_check kobject_rename(struct kobject *, const char *new_name); -extern int __must_check kobject_shadow_rename(struct kobject *kobj, - struct sysfs_dirent *new_parent, - const char *new_name); extern int __must_check kobject_move(struct kobject *, struct kobject *); extern int __must_check kobject_register(struct kobject *); diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index be8228e..c16e4c5 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -17,9 +17,6 @@ struct kobject; struct module; -struct nameidata; -struct dentry; -struct sysfs_dirent; /* FIXME * The *owner field is no longer used, but leave around @@ -94,14 +91,13 @@ extern int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), void *data, struct module *owner); extern int __must_check -sysfs_create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent_sd); +sysfs_create_dir(struct kobject *); extern void sysfs_remove_dir(struct kobject *); extern int __must_check -sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, - const char *new_name); +sysfs_rename_dir(struct kobject *kobj, const char *new_name); extern int __must_check sysfs_move_dir(struct kobject *, struct kobject *); @@ -138,12 +134,6 @@ void sysfs_remove_file_from_group(struct kobject *kobj, void sysfs_notify(struct kobject * k, char *dir, char *attr); - -extern int sysfs_make_shadowed_dir(struct kobject *kobj, - void * (*follow_link)(struct dentry *, struct nameidata *)); -extern struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj); -extern void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd); - extern int __must_check sysfs_init(void); #else /* CONFIG_SYSFS */ @@ -154,8 +144,7 @@ static inline int sysfs_schedule_callback(struct kobject *kobj, return -ENOSYS; } -static inline int sysfs_create_dir(struct kobject *kobj, - struct sysfs_dirent *shadow_parent_sd) +static inline int sysfs_create_dir(struct kobject * kobj) { return 0; } @@ -165,9 +154,7 @@ static inline void sysfs_remove_dir(struct kobject * k) ; } -static inline int sysfs_rename_dir(struct kobject *kobj, - struct sysfs_dirent *new_parent_sd, - const char *new_name) +static inline int sysfs_rename_dir(struct kobject * kobj, const char *new_name) { return 0; } @@ -242,12 +229,6 @@ static inline void sysfs_notify(struct kobject * k, char *dir, char *attr) { } -static inline int sysfs_make_shadowed_dir(struct kobject *kobj, - void * (*follow_link)(struct dentry *, struct nameidata *)) -{ - return 0; -} - static inline int __must_check sysfs_init(void) { return 0; diff --git a/lib/kobject.c b/lib/kobject.c index 10ae2eb..e8181d3 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -44,11 +44,11 @@ static int populate_dir(struct kobject * kobj) return error; } -static int create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent) +static int create_dir(struct kobject * kobj) { int error = 0; if (kobject_name(kobj)) { - error = sysfs_create_dir(kobj, shadow_parent); + error = sysfs_create_dir(kobj); if (!error) { if ((error = populate_dir(kobj))) sysfs_remove_dir(kobj); @@ -157,12 +157,11 @@ static void unlink(struct kobject * kobj) } /** - * kobject_shadow_add - add an object to the hierarchy. + * kobject_add - add an object to the hierarchy. * @kobj: object. - * @shadow_parent: sysfs directory to add to. */ -int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent) +int kobject_add(struct kobject * kobj) { int error = 0; struct kobject * parent; @@ -194,7 +193,7 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent) kobj->parent = parent; } - error = create_dir(kobj, shadow_parent); + error = create_dir(kobj); if (error) { /* unlink does the kobject_put() for us */ unlink(kobj); @@ -216,16 +215,6 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent) } /** - * kobject_add - add an object to the hierarchy. - * @kobj: object. - */ -int kobject_add(struct kobject * kobj) -{ - return kobject_shadow_add(kobj, NULL); -} - - -/** * kobject_register - initialize and add an object. * @kobj: object in question. */ @@ -334,7 +323,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name) /* Note : if we want to send the new name alone, not the full path, * we could probably use kobject_name(kobj); */ - error = sysfs_rename_dir(kobj, kobj->parent->sd, new_name); + error = sysfs_rename_dir(kobj, new_name); /* This function is mostly/only used for network interface. * Some hotplug package track interfaces by their name and @@ -351,27 +340,6 @@ out: } /** - * kobject_rename - change the name of an object - * @kobj: object in question. - * @new_parent: object's new parent - * @new_name: object's new name - */ - -int kobject_shadow_rename(struct kobject *kobj, - struct sysfs_dirent *new_parent, const char *new_name) -{ - int error = 0; - - kobj = kobject_get(kobj); - if (!kobj) - return -EINVAL; - error = sysfs_rename_dir(kobj, new_parent, new_name); - kobject_put(kobj); - - return error; -} - -/** * kobject_move - move object to another parent * @kobj: object in question. * @new_parent: object's new parent (can be NULL) -- cgit v0.10.2 From a7a0475497f9018e2e28cd421ee467d2ad68643e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 2 Aug 2007 21:38:02 +0900 Subject: sysfs: cosmetic changes in sysfs_lookup() * remove space between * and symbol name in variable declaration. * kill unnecessary new line. * kill 'found' and test 'sd' instead. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 837073d..5da8da8 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -756,24 +756,19 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct dentry *ret = NULL; - struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata; - struct sysfs_dirent * sd; + struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata; + struct sysfs_dirent *sd; struct bin_attribute *bin_attr; struct inode *inode; - int found = 0; mutex_lock(&sysfs_mutex); - for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) { - if (sysfs_type(sd) && - !strcmp(sd->s_name, dentry->d_name.name)) { - found = 1; + for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) + if (sysfs_type(sd) && !strcmp(sd->s_name, dentry->d_name.name)) break; - } - } /* no such entry */ - if (!found) + if (!sd) goto out_unlock; /* attach dentry and inode */ -- cgit v0.10.2 From ff869de7bf5e76adffebd3a176c1c73bca7eddb7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 2 Aug 2007 21:38:02 +0900 Subject: sysfs: simplify sysfs_rename_dir() With the shadow directories gone, sysfs_rename_dir() can be simplified. * parent doesn't need to be grabbed separately. Just access old_dentry->d_parent. * parent sd can never change. Remove code to move under the new parent. * Massage comments a bit. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 5da8da8..9504d4c 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -883,14 +883,10 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) struct sysfs_dirent *sd; struct dentry *parent = NULL; struct dentry *old_dentry = NULL, *new_dentry = NULL; - struct sysfs_dirent *parent_sd; const char *dup_name = NULL; int error; - if (!kobj->parent) - return -EINVAL; - - /* get dentries */ + /* get the original dentry */ sd = kobj->sd; old_dentry = sysfs_get_dentry(sd); if (IS_ERR(old_dentry)) { @@ -898,12 +894,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) goto out_dput; } - parent_sd = kobj->parent->sd; - parent = sysfs_get_dentry(parent_sd); - if (IS_ERR(parent)) { - error = PTR_ERR(parent); - goto out_dput; - } + parent = old_dentry->d_parent; /* lock parent and get dentry for new name */ mutex_lock(&parent->d_inode->i_mutex); @@ -933,22 +924,14 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) goto out_drop; mutex_lock(&sysfs_mutex); - dup_name = sd->s_name; sd->s_name = new_name; + mutex_unlock(&sysfs_mutex); - /* move under the new parent */ + /* rename */ d_add(new_dentry, NULL); d_move(sd->s_dentry, new_dentry); - sysfs_unlink_sibling(sd); - sysfs_get(parent_sd); - sysfs_put(sd->s_parent); - sd->s_parent = parent_sd; - sysfs_link_sibling(sd); - - mutex_unlock(&sysfs_mutex); - error = 0; goto out_unlock; @@ -958,7 +941,6 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) mutex_unlock(&parent->d_inode->i_mutex); out_dput: kfree(dup_name); - dput(parent); dput(old_dentry); dput(new_dentry); return error; -- cgit v0.10.2 From 41fc1c27452e041a18e5141b8203ee0ea72bc483 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 2 Aug 2007 21:38:03 +0900 Subject: sysfs: make sysfs_add/remove_one() call link/unlink_sibling() implictly When adding or removing a sysfs_dirent, the user used to be required to call link/unlink separately. It was for two reasons - code looked like that before sysfs_addrm_cxt conversion and to avoid looping through parent_sd->children list twice during removal. Performance optimization during removal just isn't worth it. Make sysfs_add/remove_one() call sysfs_link/unlink_sibing() implicitly. This makes code simpler albeit slightly less efficient. This change doesn't introduce any noticeable behavior change. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 9504d4c..354675a 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -30,7 +30,7 @@ static DEFINE_IDA(sysfs_ino_ida); * Locking: * mutex_lock(sysfs_mutex) */ -void sysfs_link_sibling(struct sysfs_dirent *sd) +static void sysfs_link_sibling(struct sysfs_dirent *sd) { struct sysfs_dirent *parent_sd = sd->s_parent; @@ -49,7 +49,7 @@ void sysfs_link_sibling(struct sysfs_dirent *sd) * Locking: * mutex_lock(sysfs_mutex) */ -void sysfs_unlink_sibling(struct sysfs_dirent *sd) +static void sysfs_unlink_sibling(struct sysfs_dirent *sd) { struct sysfs_dirent **pos; @@ -500,6 +500,8 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) inc_nlink(acxt->parent_inode); acxt->cnt++; + + sysfs_link_sibling(sd); } /** @@ -521,7 +523,9 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) */ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) { - BUG_ON(sd->s_sibling || (sd->s_flags & SYSFS_FLAG_REMOVED)); + BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); + + sysfs_unlink_sibling(sd); sd->s_flags |= SYSFS_FLAG_REMOVED; sd->s_sibling = acxt->removed; @@ -697,10 +701,8 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, /* link in */ sysfs_addrm_start(&acxt, parent_sd); - if (!sysfs_find_dirent(parent_sd, name)) { + if (!sysfs_find_dirent(parent_sd, name)) sysfs_add_one(&acxt, sd); - sysfs_link_sibling(sd); - } if (!sysfs_addrm_finish(&acxt)) { sysfs_put(sd); @@ -821,7 +823,6 @@ static void remove_dir(struct sysfs_dirent *sd) struct sysfs_addrm_cxt acxt; sysfs_addrm_start(&acxt, sd->s_parent); - sysfs_unlink_sibling(sd); sysfs_remove_one(&acxt, sd); sysfs_addrm_finish(&acxt); } @@ -846,11 +847,9 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) while (*pos) { struct sysfs_dirent *sd = *pos; - if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) { - *pos = sd->s_sibling; - sd->s_sibling = NULL; + if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) sysfs_remove_one(&acxt, sd); - } else + else pos = &(*pos)->s_sibling; } sysfs_addrm_finish(&acxt); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index b21d11b..ea0e494 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -405,10 +405,8 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, sysfs_addrm_start(&acxt, dir_sd); - if (!sysfs_find_dirent(dir_sd, attr->name)) { + if (!sysfs_find_dirent(dir_sd, attr->name)) sysfs_add_one(&acxt, sd); - sysfs_link_sibling(sd); - } if (!sysfs_addrm_finish(&acxt)) { sysfs_put(sd); diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 45128b7..efb4062 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -189,25 +189,16 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode) int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) { struct sysfs_addrm_cxt acxt; - struct sysfs_dirent **pos, *sd; + struct sysfs_dirent *sd; if (!dir_sd) return -ENOENT; sysfs_addrm_start(&acxt, dir_sd); - for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) { - sd = *pos; - - if (!sysfs_type(sd)) - continue; - if (!strcmp(sd->s_name, name)) { - *pos = sd->s_sibling; - sd->s_sibling = NULL; - sysfs_remove_one(&acxt, sd); - break; - } - } + sd = sysfs_find_dirent(dir_sd, name); + if (sd) + sysfs_remove_one(&acxt, sd); if (sysfs_addrm_finish(&acxt)) return 0; diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 9048453..c129f30 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -92,10 +92,8 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char sysfs_addrm_start(&acxt, parent_sd); - if (!sysfs_find_dirent(parent_sd, name)) { + if (!sysfs_find_dirent(parent_sd, name)) sysfs_add_one(&acxt, sd); - sysfs_link_sibling(sd); - } if (!sysfs_addrm_finish(&acxt)) { error = -EEXIST; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index b55e510..32b8b64 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -56,8 +56,6 @@ extern struct sysfs_dirent sysfs_root; extern struct kmem_cache *sysfs_dir_cachep; extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); -extern void sysfs_link_sibling(struct sysfs_dirent *sd); -extern void sysfs_unlink_sibling(struct sysfs_dirent *sd); extern struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); extern void sysfs_put_active(struct sysfs_dirent *sd); extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); -- cgit v0.10.2 From 23dc279950a056c33a14d09cf759f5173d41abd9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 2 Aug 2007 21:38:03 +0900 Subject: sysfs: make sysfs_add_one() automatically check for duplicate entry Make sysfs_add_one() check for duplicate entry and return -EEXIST if such entry exists. This simplifies node addition code a bit. This patch doesn't introduce any noticeable behavior change. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 354675a..6206032 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -491,9 +491,16 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, * * LOCKING: * Determined by sysfs_addrm_start(). + * + * RETURNS: + * 0 on success, -EEXIST if entry with the given name already + * exists. */ -void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) +int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) { + if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) + return -EEXIST; + sd->s_parent = sysfs_get(acxt->parent_sd); if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) @@ -502,6 +509,8 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) acxt->cnt++; sysfs_link_sibling(sd); + + return 0; } /** @@ -691,6 +700,7 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; + int rc; /* allocate */ sd = sysfs_new_dirent(name, mode, SYSFS_DIR); @@ -700,17 +710,15 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, /* link in */ sysfs_addrm_start(&acxt, parent_sd); + rc = sysfs_add_one(&acxt, sd); + sysfs_addrm_finish(&acxt); - if (!sysfs_find_dirent(parent_sd, name)) - sysfs_add_one(&acxt, sd); - - if (!sysfs_addrm_finish(&acxt)) { + if (rc == 0) + *p_sd = sd; + else sysfs_put(sd); - return -EEXIST; - } - *p_sd = sd; - return 0; + return rc; } int sysfs_create_subdir(struct kobject *kobj, const char *name, diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index ea0e494..33bb340 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -397,6 +397,7 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; + int rc; sd = sysfs_new_dirent(attr->name, mode, type); if (!sd) @@ -404,16 +405,13 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, sd->s_elem.attr.attr = (void *)attr; sysfs_addrm_start(&acxt, dir_sd); + rc = sysfs_add_one(&acxt, sd); + sysfs_addrm_finish(&acxt); - if (!sysfs_find_dirent(dir_sd, attr->name)) - sysfs_add_one(&acxt, sd); - - if (!sysfs_addrm_finish(&acxt)) { + if (rc) sysfs_put(sd); - return -EEXIST; - } - return 0; + return rc; } diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index c129f30..a6b13f1 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -91,14 +91,11 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char target_sd = NULL; /* reference is now owned by the symlink */ sysfs_addrm_start(&acxt, parent_sd); + error = sysfs_add_one(&acxt, sd); + sysfs_addrm_finish(&acxt); - if (!sysfs_find_dirent(parent_sd, name)) - sysfs_add_one(&acxt, sd); - - if (!sysfs_addrm_finish(&acxt)) { - error = -EEXIST; + if (error) goto out_put; - } return 0; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 32b8b64..bb3f0c9 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -62,7 +62,7 @@ extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); extern void sysfs_put_active_two(struct sysfs_dirent *sd); extern void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *parent_sd); -extern void sysfs_add_one(struct sysfs_addrm_cxt *acxt, +extern int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); -- cgit v0.10.2 From 990e53f880be9ff93072b4cce590ec2826cee0b6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 2 Aug 2007 21:38:03 +0900 Subject: sysfs: make sysfs_addrm_finish() return void With the previous sysfs_add_one() update, there is only one user of the return value of sysfs_addrm_finish() and the user can switch to testing @sd easily. Make sysfs_addrm_finish() return void for cleaner semantics as suggested by Satyam Sharma. This patch doesn't introduce any noticeable behavior change. Signed-off-by: Tejun Heo Cc: Satyam Sharma Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 6206032..a0da2b0 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -609,11 +609,8 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd) * * LOCKING: * All mutexes acquired by sysfs_addrm_start() are released. - * - * RETURNS: - * Number of added/removed sysfs_dirents since sysfs_addrm_start(). */ -int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) +void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) { /* release resources acquired by sysfs_addrm_start() */ mutex_unlock(&sysfs_mutex); @@ -639,8 +636,6 @@ int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) sysfs_deactivate(sd); sysfs_put(sd); } - - return acxt->cnt; } /** diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index efb4062..e22db6c 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -200,7 +200,10 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) if (sd) sysfs_remove_one(&acxt, sd); - if (sysfs_addrm_finish(&acxt)) + sysfs_addrm_finish(&acxt); + + if (sd) return 0; - return -ENOENT; + else + return -ENOENT; } diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index bb3f0c9..0436754 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -66,7 +66,7 @@ extern int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); -extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); +extern void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd); extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode); -- cgit v0.10.2 From 6374475661172d508a9b93a2740a3fdc9d899756 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 13 Aug 2007 11:24:33 +0200 Subject: dmi-id: Use dynamic sysfs attributes We can use sysfs attributes with an extra parameter for dmi id attributes. This makes it possible to use the same callback function for all attributes, reducing the binary size significantly (-18% on x86_64.) Signed-off-by: Jean Delvare Acked-by: Lennart Poettering Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index 2678098..a7bd87d 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -13,21 +13,35 @@ #include #include +struct dmi_device_attribute{ + struct device_attribute dev_attr; + int field; +}; +#define to_dmi_dev_attr(_dev_attr) \ + container_of(_dev_attr, struct dmi_device_attribute, dev_attr) + #define DEFINE_DMI_ATTR(_name, _mode, _show) \ static struct device_attribute sys_dmi_##_name##_attr = \ __ATTR(_name, _mode, _show, NULL); -#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \ -static ssize_t sys_dmi_##_name##_show(struct device *dev, \ - struct device_attribute *attr, \ - char *page) \ -{ \ - ssize_t len; \ - len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(_field)); \ - page[len-1] = '\n'; \ - return len; \ -} \ -DEFINE_DMI_ATTR(_name, _mode, sys_dmi_##_name##_show); +static ssize_t sys_dmi_field_show(struct device *dev, + struct device_attribute *attr, + char *page) +{ + int field = to_dmi_dev_attr(attr)->field; + ssize_t len; + len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(field)); + page[len-1] = '\n'; + return len; +} + +#define DMI_ATTR(_name, _mode, _show, _field) \ + { .dev_attr = __ATTR(_name, _mode, _show, NULL), \ + .field = _field } + +#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \ +static struct dmi_device_attribute sys_dmi_##_name##_attr = \ + DMI_ATTR(_name, _mode, sys_dmi_field_show, _field); DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor, 0444, DMI_BIOS_VENDOR); DEFINE_DMI_ATTR_WITH_SHOW(bios_version, 0444, DMI_BIOS_VERSION); @@ -160,7 +174,7 @@ static struct device *dmi_dev; #define ADD_DMI_ATTR(_name, _field) \ if (dmi_get_system_info(_field)) \ - sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr; + sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr; extern int dmi_available; -- cgit v0.10.2 From 34b51f39e23bc9e529830ddf6108381d4bab95a6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 13 Aug 2007 11:26:26 +0200 Subject: dmi-id: Possible cleanup The DEFINE_DMI_ATTR macro has a single user left so we can expand it for slightly shorter/simpler code. Signed-off-by: Jean Delvare Acked-by: Lennart Poettering Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index a7bd87d..b6e1eb7 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -20,10 +20,6 @@ struct dmi_device_attribute{ #define to_dmi_dev_attr(_dev_attr) \ container_of(_dev_attr, struct dmi_device_attribute, dev_attr) -#define DEFINE_DMI_ATTR(_name, _mode, _show) \ -static struct device_attribute sys_dmi_##_name##_attr = \ - __ATTR(_name, _mode, _show, NULL); - static ssize_t sys_dmi_field_show(struct device *dev, struct device_attribute *attr, char *page) @@ -135,7 +131,8 @@ static ssize_t sys_dmi_modalias_show(struct device *dev, return r+1; } -DEFINE_DMI_ATTR(modalias, 0444, sys_dmi_modalias_show); +static struct device_attribute sys_dmi_modalias_attr = + __ATTR(modalias, 0444, sys_dmi_modalias_show, NULL); static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2]; -- cgit v0.10.2 From 60043428a561a5d431ad479b7ecb79805ed04efc Mon Sep 17 00:00:00 2001 From: "tonyj@suse.de" Date: Tue, 7 Aug 2007 22:28:47 -0700 Subject: Convert from class_device to device for drivers/video Convert from class_device to device for drivers/video. Signed-off-by: Tony Jones Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index d05891f..b8a2095 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -316,7 +316,7 @@ static int acpi_video_output_get(struct output_device *od) { unsigned long state; struct acpi_video_device *vd = - (struct acpi_video_device *)class_get_devdata(&od->class_dev); + (struct acpi_video_device *)dev_get_drvdata(&od->dev); acpi_video_device_get_state(vd, &state); return (int)state; } @@ -325,7 +325,7 @@ static int acpi_video_output_set(struct output_device *od) { unsigned long state = od->request_state; struct acpi_video_device *vd= - (struct acpi_video_device *)class_get_devdata(&od->class_dev); + (struct acpi_video_device *)dev_get_drvdata(&od->dev); return acpi_video_device_set_state(vd, state); } diff --git a/drivers/video/output.c b/drivers/video/output.c index 1473f2c..f2df551 100644 --- a/drivers/video/output.c +++ b/drivers/video/output.c @@ -31,7 +31,8 @@ MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luming Yu "); -static ssize_t video_output_show_state(struct class_device *dev,char *buf) +static ssize_t video_output_show_state(struct device *dev, + struct device_attribute *attr, char *buf) { ssize_t ret_size = 0; struct output_device *od = to_output_device(dev); @@ -40,8 +41,9 @@ static ssize_t video_output_show_state(struct class_device *dev,char *buf) return ret_size; } -static ssize_t video_output_store_state(struct class_device *dev, - const char *buf,size_t count) +static ssize_t video_output_store_state(struct device *dev, + struct device_attribute *attr, + const char *buf,size_t count) { char *endp; struct output_device *od = to_output_device(dev); @@ -60,21 +62,22 @@ static ssize_t video_output_store_state(struct class_device *dev, return count; } -static void video_output_class_release(struct class_device *dev) +static void video_output_release(struct device *dev) { struct output_device *od = to_output_device(dev); kfree(od); } -static struct class_device_attribute video_output_attributes[] = { +static struct device_attribute video_output_attributes[] = { __ATTR(state, 0644, video_output_show_state, video_output_store_state), __ATTR_NULL, }; + static struct class video_output_class = { .name = "video_output", - .release = video_output_class_release, - .class_dev_attrs = video_output_attributes, + .dev_release = video_output_release, + .dev_attrs = video_output_attributes, }; struct output_device *video_output_register(const char *name, @@ -91,11 +94,11 @@ struct output_device *video_output_register(const char *name, goto error_return; } new_dev->props = op; - new_dev->class_dev.class = &video_output_class; - new_dev->class_dev.dev = dev; - strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN); - class_set_devdata(&new_dev->class_dev,devdata); - ret_code = class_device_register(&new_dev->class_dev); + new_dev->dev.class = &video_output_class; + new_dev->dev.parent = dev; + strlcpy(new_dev->dev.bus_id,name, BUS_ID_SIZE); + dev_set_drvdata(&new_dev->dev, devdata); + ret_code = device_register(&new_dev->dev); if (ret_code) { kfree(new_dev); goto error_return; @@ -111,7 +114,7 @@ void video_output_unregister(struct output_device *dev) { if (!dev) return; - class_device_unregister(&dev->class_dev); + device_unregister(&dev->dev); } EXPORT_SYMBOL(video_output_unregister); diff --git a/include/linux/video_output.h b/include/linux/video_output.h index e63e0c0..2fb46bc 100644 --- a/include/linux/video_output.h +++ b/include/linux/video_output.h @@ -31,9 +31,9 @@ struct output_properties { struct output_device { int request_state; struct output_properties *props; - struct class_device class_dev; + struct device dev; }; -#define to_output_device(obj) container_of(obj, struct output_device, class_dev) +#define to_output_device(obj) container_of(obj, struct output_device, dev) struct output_device *video_output_register(const char *name, struct device *dev, void *devdata, -- cgit v0.10.2 From 07c015e7654821f2dda00dcf152c65b2afd46ac3 Mon Sep 17 00:00:00 2001 From: "tonyj@suse.de" Date: Tue, 7 Aug 2007 22:28:44 -0700 Subject: Convert from class_device to device in drivers/char Convert from class_device to device in drivers/char. Signed-off-by: Tony Jones Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 9b8278e..acbfe1c 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -513,7 +513,7 @@ static int __init dsp56k_init_driver(void) err = PTR_ERR(dsp56k_class); goto out_chrdev; } - class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k"); + device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), "dsp56k"); printk(banner); goto out; @@ -527,7 +527,7 @@ module_init(dsp56k_init_driver); static void __exit dsp56k_cleanup_driver(void) { - class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); + device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); class_destroy(dsp56k_class); unregister_chrdev(DSP56K_MAJOR, "dsp56k"); } diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 8d74b8745e..bd94d5f 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -411,8 +411,8 @@ cleanup_module(void) iiResetDelay( i2BoardPtrTable[i] ); /* free io addresses and Tibet */ release_region( ip2config.addr[i], 8 ); - class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); - class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); + device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); + device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); } /* Disable and remove interrupt handler. */ if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { @@ -718,12 +718,12 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) } if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { - class_device_create(ip2_class, NULL, + device_create(ip2_class, NULL, MKDEV(IP2_IPL_MAJOR, 4 * i), - NULL, "ipl%d", i); - class_device_create(ip2_class, NULL, + "ipl%d", i); + device_create(ip2_class, NULL, MKDEV(IP2_IPL_MAJOR, 4 * i + 1), - NULL, "stat%d", i); + "stat%d", i); for ( box = 0; box < ABS_MAX_BOXES; ++box ) { diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index c2aa44e..0246a2b8 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -865,7 +865,7 @@ static void ipmi_new_smi(int if_num, struct device *device) entry->dev = dev; mutex_lock(®_list_mutex); - class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num); + device_create(ipmi_class, device, dev, "ipmi%d", if_num); list_add(&entry->link, ®_list); mutex_unlock(®_list_mutex); } @@ -883,7 +883,7 @@ static void ipmi_smi_gone(int if_num) break; } } - class_device_destroy(ipmi_class, dev); + device_destroy(ipmi_class, dev); mutex_unlock(®_list_mutex); } @@ -938,7 +938,7 @@ static __exit void cleanup_ipmi(void) mutex_lock(®_list_mutex); list_for_each_entry_safe(entry, entry2, ®_list, link) { list_del(&entry->link); - class_device_destroy(ipmi_class, entry->dev); + device_destroy(ipmi_class, entry->dev); kfree(entry); } mutex_unlock(®_list_mutex); diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 3c66f40..1f27be1 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -4624,9 +4624,8 @@ static int __init istallion_module_init(void) istallion_class = class_create(THIS_MODULE, "staliomem"); for (i = 0; i < 4; i++) - class_device_create(istallion_class, NULL, - MKDEV(STL_SIOMEMMAJOR, i), - NULL, "staliomem%d", i); + device_create(istallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), + "staliomem%d", i); return 0; err_deinit: @@ -4659,8 +4658,7 @@ static void __exit istallion_module_exit(void) unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); for (j = 0; j < 4; j++) - class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, - j)); + device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j)); class_destroy(istallion_class); pci_unregister_driver(&stli_pcidriver); diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 62051f8..c59e2a0 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -799,8 +799,7 @@ static int lp_register(int nr, struct parport *port) if (reset) lp_reset(nr); - class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev, - "lp%d", nr); + device_create(lp_class, port->dev, MKDEV(LP_MAJOR, nr), "lp%d", nr); printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven"); @@ -971,7 +970,7 @@ static void lp_cleanup_module (void) if (lp_table[offset].dev == NULL) continue; parport_unregister_device(lp_table[offset].dev); - class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset)); + device_destroy(lp_class, MKDEV(LP_MAJOR, offset)); } class_destroy(lp_class); } diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 4177f6d..cc5d777 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -1863,8 +1863,7 @@ static int cm4000_probe(struct pcmcia_device *link) return ret; } - class_device_create(cmm_class, NULL, MKDEV(major, i), NULL, - "cmm%d", i); + device_create(cmm_class, NULL, MKDEV(major, i), "cmm%d", i); return 0; } @@ -1888,7 +1887,7 @@ static void cm4000_detach(struct pcmcia_device *link) dev_table[devno] = NULL; kfree(dev); - class_device_destroy(cmm_class, MKDEV(major, devno)); + device_destroy(cmm_class, MKDEV(major, devno)); return; } diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index b24a3e7..a0b9c87 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -642,8 +642,7 @@ static int reader_probe(struct pcmcia_device *link) return ret; } - class_device_create(cmx_class, NULL, MKDEV(major, i), NULL, - "cmx%d", i); + device_create(cmx_class, NULL, MKDEV(major, i), "cmx%d", i); return 0; } @@ -666,7 +665,7 @@ static void reader_detach(struct pcmcia_device *link) dev_table[devno] = NULL; kfree(dev); - class_device_destroy(cmx_class, MKDEV(major, devno)); + device_destroy(cmx_class, MKDEV(major, devno)); return; } diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 52753e7..b9c1dba 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -441,8 +441,7 @@ scdrv_init(void) continue; } - class_device_create(snsc_class, NULL, dev, NULL, - "%s", devname); + device_create(snsc_class, NULL, dev, "%s", devname); ia64_sn_irtr_intr_enable(scd->scd_nasid, 0 /*ignored */ , diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 4a80b2f..45758d5 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -4778,9 +4778,8 @@ static int __init stallion_module_init(void) if (IS_ERR(stallion_class)) printk("STALLION: failed to create class\n"); for (i = 0; i < 4; i++) - class_device_create(stallion_class, NULL, - MKDEV(STL_SIOMEMMAJOR, i), NULL, - "staliomem%d", i); + device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), + "staliomem%d", i); return 0; err_unrtty: @@ -4816,7 +4815,7 @@ static void __exit stallion_module_exit(void) } for (i = 0; i < 4; i++) - class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); + device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); class_destroy(stallion_class); diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index 35b40b9..cef55c4 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -441,8 +441,8 @@ tipar_register(int nr, struct parport *port) goto out; } - class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR, - TIPAR_MINOR + nr), port->dev, "par%d", nr); + device_create(tipar_class, port->dev, MKDEV(TIPAR_MAJOR, + TIPAR_MINOR + nr), "par%d", nr); /* Display informations */ pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq == @@ -534,7 +534,7 @@ tipar_cleanup_module(void) if (table[i].dev == NULL) continue; parport_unregister_device(table[i].dev); - class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); + device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); } class_destroy(tipar_class); diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index f1d60f0..db7a731 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -871,10 +871,10 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) state[i].cur_part = 0; for (j = 0; j < MAX_PARTITIONS; ++j) state[i].part_stat_rwi[j] = VIOT_IDLE; - class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL, + device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), "iseries!vt%d", i); - class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), - NULL, "iseries!nvt%d", i); + device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), + "iseries!nvt%d", i); printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries " "resource %10.10s type %4.4s, model %3.3s\n", i, viotape_unitinfo[i].rsrcname, @@ -886,8 +886,8 @@ static int viotape_remove(struct vio_dev *vdev) { int i = vdev->unit_address; - class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); - class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); + device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); + device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); return 0; } -- cgit v0.10.2 From 5c5daf657cb5f963a38413f2852279d7a3843144 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 12 Aug 2007 20:43:55 +0200 Subject: Driver core: exclude kobject_uevent.c for !CONFIG_HOTPLUG Move uevent specific logic from the core into kobject_uevent.c, which does no longer require to link the unused string array if hotplug is not compiled in. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/core.c b/drivers/base/core.c index d487c03..65de221 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -234,13 +234,11 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, /* search the kset, the device belongs to */ top_kobj = &dev->kobj; - if (!top_kobj->kset && top_kobj->parent) { - do { - top_kobj = top_kobj->parent; - } while (!top_kobj->kset && top_kobj->parent); - } + while (!top_kobj->kset && top_kobj->parent) + top_kobj = top_kobj->parent; if (!top_kobj->kset) goto out; + kset = top_kobj->kset; if (!kset->uevent_ops || !kset->uevent_ops->uevent) goto out; @@ -270,17 +268,9 @@ out: static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - size_t len = count; enum kobject_action action; - if (len && buf[len-1] == '\n') - len--; - - for (action = 0; action < KOBJ_MAX; action++) { - if (strncmp(kobject_actions[action], buf, len) != 0) - continue; - if (kobject_actions[action][len] != '\0') - continue; + if (kobject_action_type(buf, count, &action) == 0) { kobject_uevent(&dev->kobj, action); goto out; } diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 56f5eaf..0777b3f 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -58,9 +58,6 @@ enum kobject_action { KOBJ_MAX }; -/* The list of strings defining the valid kobject actions as specified above */ -extern const char *kobject_actions[]; - struct kobject { const char * k_name; struct kref kref; @@ -241,6 +238,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) __attribute__((format (printf, 2, 3))); + +int kobject_action_type(const char *buf, size_t count, + enum kobject_action *type); #else static inline int kobject_uevent(struct kobject *kobj, enum kobject_action action) { return 0; } @@ -251,6 +251,10 @@ static inline int kobject_uevent_env(struct kobject *kobj, static inline int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) { return 0; } + +static inline int kobject_action_type(const char *buf, size_t count, + enum kobject_action *type) +{ return -EINVAL; } #endif #endif /* __KERNEL__ */ diff --git a/lib/Makefile b/lib/Makefile index 4f3f3e2..6c4ea33 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -10,7 +10,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ lib-$(CONFIG_MMU) += ioremap.o lib-$(CONFIG_SMP) += cpumask.o -lib-y += kobject.o kref.o kobject_uevent.o klist.o +lib-y += kobject.o kref.o klist.o obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o @@ -20,6 +20,7 @@ CFLAGS_kobject.o += -DDEBUG CFLAGS_kobject_uevent.o += -DDEBUG endif +lib-$(CONFIG_HOTPLUG) += kobject_uevent.o obj-$(CONFIG_GENERIC_IOMAP) += iomap.o obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 5ccda46..a8efb48 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -23,17 +23,6 @@ #include -/* the strings here must match the enum in include/linux/kobject.h */ -const char *kobject_actions[] = { - "add", - "remove", - "change", - "move", - "online", - "offline", -}; - -#if defined(CONFIG_HOTPLUG) u64 uevent_seqnum; char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; static DEFINE_SPINLOCK(sequence_lock); @@ -41,6 +30,50 @@ static DEFINE_SPINLOCK(sequence_lock); static struct sock *uevent_sock; #endif +/* the strings here must match the enum in include/linux/kobject.h */ +static const char *kobject_actions[] = { + [KOBJ_ADD] = "add", + [KOBJ_REMOVE] = "remove", + [KOBJ_CHANGE] = "change", + [KOBJ_MOVE] = "move", + [KOBJ_ONLINE] = "online", + [KOBJ_OFFLINE] = "offline", +}; + +/** + * kobject_action_type - translate action string to numeric type + * + * @buf: buffer containing the action string, newline is ignored + * @len: length of buffer + * @type: pointer to the location to store the action type + * + * Returns 0 if the action string was recognized. + */ +int kobject_action_type(const char *buf, size_t count, + enum kobject_action *type) +{ + enum kobject_action action; + int ret = -EINVAL; + + if (count && buf[count-1] == '\n') + count--; + + if (!count) + goto out; + + for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) { + if (strncmp(kobject_actions[action], buf, count) != 0) + continue; + if (kobject_actions[action][count] != '\0') + continue; + *type = action; + ret = 0; + break; + } +out: + return ret; +} + /** * kobject_uevent_env - send an uevent with environmental data * @@ -270,5 +303,3 @@ static int __init kobject_uevent_init(void) postcore_initcall(kobject_uevent_init); #endif - -#endif /* CONFIG_HOTPLUG */ -- cgit v0.10.2 From 7ac1cf4a87f446c130f7d8a4fe7e519f532a11de Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 12 Aug 2007 20:43:55 +0200 Subject: Driver core: add uevent file for bus and driver This has been in the SuSE kernels for some time now. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 0a8d075..6768a01 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -610,6 +610,17 @@ static inline int add_probe_files(struct bus_type *bus) { return 0; } static inline void remove_probe_files(struct bus_type *bus) {} #endif +static ssize_t driver_uevent_store(struct device_driver *drv, + const char *buf, size_t count) +{ + enum kobject_action action; + + if (kobject_action_type(buf, count, &action) == 0) + kobject_uevent(&drv->kobj, action); + return count; +} +static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store); + /** * bus_add_driver - Add a driver to the bus. * @drv: driver. @@ -640,6 +651,11 @@ int bus_add_driver(struct device_driver *drv) klist_add_tail(&drv->knode_bus, &bus->klist_drivers); module_add_driver(drv->owner, drv); + error = driver_create_file(drv, &driver_attr_uevent); + if (error) { + printk(KERN_ERR "%s: uevent attr (%s) failed\n", + __FUNCTION__, drv->name); + } error = driver_add_attrs(bus, drv); if (error) { /* How the hell do we get out of this pickle? Give up */ @@ -677,6 +693,7 @@ void bus_remove_driver(struct device_driver * drv) remove_bind_files(drv); driver_remove_attrs(drv->bus, drv); + driver_remove_file(drv, &driver_attr_uevent); klist_remove(&drv->knode_bus); pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); driver_detach(drv); @@ -804,6 +821,17 @@ static void klist_devices_put(struct klist_node *n) put_device(dev); } +static ssize_t bus_uevent_store(struct bus_type *bus, + const char *buf, size_t count) +{ + enum kobject_action action; + + if (kobject_action_type(buf, count, &action) == 0) + kobject_uevent(&bus->subsys.kobj, action); + return count; +} +static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); + /** * bus_register - register a bus with the system. * @bus: bus. @@ -828,6 +856,10 @@ int bus_register(struct bus_type * bus) if (retval) goto out; + retval = bus_create_file(bus, &bus_attr_uevent); + if (retval) + goto bus_uevent_fail; + kobject_set_name(&bus->devices.kobj, "devices"); bus->devices.kobj.parent = &bus->subsys.kobj; retval = kset_register(&bus->devices); @@ -863,6 +895,8 @@ bus_probe_files_fail: bus_drivers_fail: kset_unregister(&bus->devices); bus_devices_fail: + bus_remove_file(bus, &bus_attr_uevent); +bus_uevent_fail: subsystem_unregister(&bus->subsys); out: return retval; @@ -882,6 +916,7 @@ void bus_unregister(struct bus_type * bus) remove_probe_files(bus); kset_unregister(&bus->drivers); kset_unregister(&bus->devices); + bus_remove_file(bus, &bus_attr_uevent); subsystem_unregister(&bus->subsys); } -- cgit v0.10.2 From ccd490a3c3d9c5960c738c2720fb2dc6830bc334 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 12 Aug 2007 20:43:55 +0200 Subject: Driver core: kerneldoc - kobject_uevent_env is not "usually KOBJ_MOVE" Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index a8efb48..2e4eae5 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -77,7 +77,7 @@ out: /** * kobject_uevent_env - send an uevent with environmental data * - * @action: action that is happening (usually KOBJ_MOVE) + * @action: action that is happening * @kobj: struct kobject that the action is happening to * @envp_ext: pointer to environmental data * @@ -102,9 +102,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, /* search the kset we belong to */ top_kobj = kobj; - while (!top_kobj->kset && top_kobj->parent) { + while (!top_kobj->kset && top_kobj->parent) top_kobj = top_kobj->parent; - } + if (!top_kobj->kset) { pr_debug("kobject attempted to send uevent without kset!\n"); return -EINVAL; @@ -237,7 +237,7 @@ EXPORT_SYMBOL_GPL(kobject_uevent_env); /** * kobject_uevent - notify userspace by ending an uevent * - * @action: action that is happening (usually KOBJ_ADD and KOBJ_REMOVE) + * @action: action that is happening * @kobj: struct kobject that the action is happening to * * Returns 0 if kobject_uevent() is completed with success or the -- cgit v0.10.2 From 109f0e93b6b728f03c1eb4af02bc25d71b646c59 Mon Sep 17 00:00:00 2001 From: Markus Rechberger Date: Mon, 13 Aug 2007 19:20:43 +0200 Subject: Fix Firmware class name collision following patch fixes the i2c name collision with i2c-dev. http://mcentral.de/wiki/index.php/Bugtracker#i2c_core_problem This issue has been experienced with em28xx and saa7133 based devices. I discussed that problem with Jean Delvare a while ago and he proposed to add a prefix to the class name. Signed-off-by: Markus Rechberger Acked-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 4a1b9bf..0295855 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -292,8 +292,7 @@ firmware_class_timeout(u_long data) static inline void fw_setup_device_id(struct device *f_dev, struct device *dev) { - /* XXX warning we should watch out for name collisions */ - strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE); + snprintf(f_dev->bus_id, BUS_ID_SIZE, "firmware-%s", dev->bus_id); } static int fw_register_device(struct device **dev_p, const char *fw_name, -- cgit v0.10.2 From b4d1eb2ccecb76bce4c2125c5a3e77753fcfaeb0 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 10 Aug 2007 13:51:09 -0700 Subject: drivers/base/power/: make 2 functions static suspend_device() and resume_device() can now become static. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 8ba0830..49e64db 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -55,12 +55,6 @@ extern void dpm_sysfs_remove(struct device *); extern void dpm_resume(void); extern void dpm_power_up(void); -extern int resume_device(struct device *); - -/* - * suspend.c - */ -extern int suspend_device(struct device *, pm_message_t); #else /* CONFIG_PM_SLEEP */ diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index 00fd84a..67948ba 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c @@ -20,7 +20,7 @@ * */ -int resume_device(struct device * dev) +static int resume_device(struct device * dev) { int error = 0; diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 26df9b2..204517a 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -54,7 +54,7 @@ suspend_device_dbg(struct device *dev, pm_message_t state, char *info) * @state: Power state device is entering. */ -int suspend_device(struct device * dev, pm_message_t state) +static int suspend_device(struct device * dev, pm_message_t state) { int error = 0; -- cgit v0.10.2 From a93720eeb4b3bedc1fe15e4b6ca364e6be577d20 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Fri, 10 Aug 2007 13:51:07 -0700 Subject: sysfs: Fix typos in fs/sysfs/file.c Signed-off-by: Rolf Eike Beer Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 33bb340..16f39c3 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -335,7 +335,7 @@ static int sysfs_release(struct inode * inode, struct file * filp) * again will not get new data, or reset the state of 'poll'. * Reminder: this only works for attributes which actively support * it, and it is not possible to test an attribute from userspace - * to see if it supports poll (Nether 'poll' or 'select' return + * to see if it supports poll (Neither 'poll' nor 'select' return * an appropriate error code). When in doubt, set a suitable timeout value. */ static unsigned int sysfs_poll(struct file *filp, poll_table *wait) -- cgit v0.10.2 From 44b760a825fae65629fb04b1deeab68c6bef5c50 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 19 Aug 2007 16:51:14 +0900 Subject: sysdev: remove global sysdev drivers list No one uses sysdev_drivers. Because no one calls sysdev_driver_register with NULL class. And it is difficult to imagine that someone want to implement a global sysdev driver which is called with all sys_device on any kind of sysdev_class. So this patch removes global sysdev_drivers list and update comments for this change. Signed-off-by: Akinobu Mita Cc: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 7ad8931..ac7ff6d 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -153,25 +153,22 @@ void sysdev_class_unregister(struct sysdev_class * cls) EXPORT_SYMBOL_GPL(sysdev_class_register); EXPORT_SYMBOL_GPL(sysdev_class_unregister); - -static LIST_HEAD(sysdev_drivers); static DEFINE_MUTEX(sysdev_drivers_lock); /** * sysdev_driver_register - Register auxillary driver - * @cls: Device class driver belongs to. + * @cls: Device class driver belongs to. * @drv: Driver. * - * If @cls is valid, then @drv is inserted into @cls->drivers to be + * @drv is inserted into @cls->drivers to be * called on each operation on devices of that class. The refcount * of @cls is incremented. - * Otherwise, @drv is inserted into sysdev_drivers, and called for - * each device. */ -int sysdev_driver_register(struct sysdev_class * cls, - struct sysdev_driver * drv) +int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) { + int err = 0; + mutex_lock(&sysdev_drivers_lock); if (cls && kset_get(&cls->kset)) { list_add_tail(&drv->entry, &cls->drivers); @@ -182,10 +179,13 @@ int sysdev_driver_register(struct sysdev_class * cls, list_for_each_entry(dev, &cls->kset.list, kobj.entry) drv->add(dev); } - } else - list_add_tail(&drv->entry, &sysdev_drivers); + } else { + err = -EINVAL; + printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__); + WARN_ON(1); + } mutex_unlock(&sysdev_drivers_lock); - return 0; + return err; } @@ -251,12 +251,6 @@ int sysdev_register(struct sys_device * sysdev) * code that should have called us. */ - /* Notify global drivers */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->add) - drv->add(sysdev); - } - /* Notify class auxillary drivers */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->add) @@ -272,11 +266,6 @@ void sysdev_unregister(struct sys_device * sysdev) struct sysdev_driver * drv; mutex_lock(&sysdev_drivers_lock); - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->remove) - drv->remove(sysdev); - } - list_for_each_entry(drv, &sysdev->cls->drivers, entry) { if (drv->remove) drv->remove(sysdev); @@ -293,7 +282,7 @@ void sysdev_unregister(struct sys_device * sysdev) * * Loop over each class of system devices, and the devices in each * of those classes. For each device, we call the shutdown method for - * each driver registered for the device - the globals, the auxillaries, + * each driver registered for the device - the auxillaries, * and the class driver. * * Note: The list is iterated in reverse order, so that we shut down @@ -320,13 +309,7 @@ void sysdev_shutdown(void) struct sysdev_driver * drv; pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - /* Call global drivers first. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->shutdown) - drv->shutdown(sysdev); - } - - /* Call auxillary drivers next. */ + /* Call auxillary drivers first */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->shutdown) drv->shutdown(sysdev); @@ -354,12 +337,6 @@ static void __sysdev_resume(struct sys_device *dev) if (drv->resume) drv->resume(dev); } - - /* Call global drivers. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->resume) - drv->resume(dev); - } } /** @@ -393,16 +370,7 @@ int sysdev_suspend(pm_message_t state) list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - /* Call global drivers first. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->suspend) { - ret = drv->suspend(sysdev, state); - if (ret) - goto gbl_driver; - } - } - - /* Call auxillary drivers next. */ + /* Call auxillary drivers first */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->suspend) { ret = drv->suspend(sysdev, state); @@ -436,18 +404,7 @@ aux_driver: if (err_drv->resume) err_drv->resume(sysdev); } - drv = NULL; -gbl_driver: - if (drv) - printk(KERN_ERR "sysdev driver suspend failed for %s\n", - kobject_name(&sysdev->kobj)); - list_for_each_entry(err_drv, &sysdev_drivers, entry) { - if (err_drv == drv) - break; - if (err_drv->resume) - err_drv->resume(sysdev); - } /* resume other sysdevs in current class */ list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { if (err_dev == sysdev) -- cgit v0.10.2 From 1359555eb77d240b7c1d7ee75bb07e89e89770e4 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 9 Sep 2007 12:54:16 +0200 Subject: Driver core: Make platform_device.id an int While platform_device.id is a u32, platform_device_add() handles "-1" as a special id value. This has potential for confusion and bugs. Making it an int instead should prevent problems from happening in the future. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/platform.c b/drivers/base/platform.c index a2e3910..fb56092 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -161,7 +161,7 @@ static void platform_device_release(struct device *dev) * Create a platform device object which can have other objects attached * to it, and which will have attached objects freed when it is released. */ -struct platform_device *platform_device_alloc(const char *name, unsigned int id) +struct platform_device *platform_device_alloc(const char *name, int id) { struct platform_object *pa; @@ -245,7 +245,8 @@ int platform_device_add(struct platform_device *pdev) pdev->dev.bus = &platform_bus_type; if (pdev->id != -1) - snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id); + snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name, + pdev->id); else strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE); @@ -359,7 +360,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister); * the Linux driver model. In particular, when such drivers are built * as modules, they can't be "hotplugged". */ -struct platform_device *platform_device_register_simple(char *name, unsigned int id, +struct platform_device *platform_device_register_simple(char *name, int id, struct resource *res, unsigned int num) { struct platform_device *pdev; diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 8bbd459..e808043 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -15,7 +15,7 @@ struct platform_device { const char * name; - u32 id; + int id; struct device dev; u32 num_resources; struct resource * resource; @@ -35,9 +35,10 @@ extern struct resource *platform_get_resource_byname(struct platform_device *, u extern int platform_get_irq_byname(struct platform_device *, char *); extern int platform_add_devices(struct platform_device **, int); -extern struct platform_device *platform_device_register_simple(char *, unsigned int, struct resource *, unsigned int); +extern struct platform_device *platform_device_register_simple(char *, int id, + struct resource *, unsigned int); -extern struct platform_device *platform_device_alloc(const char *name, unsigned int id); +extern struct platform_device *platform_device_alloc(const char *name, int id); extern int platform_device_add_resources(struct platform_device *pdev, struct resource *res, unsigned int num); extern int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size); extern int platform_device_add(struct platform_device *pdev); -- cgit v0.10.2 From 253280267a7f1ced0c434fb24b7bef92d7d22628 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 20 Aug 2007 21:36:29 +0900 Subject: sysfs: fix i_mutex locking in sysfs_get_dentry() lookup_one_len_kern() should be called with the parent's i_mutex locked. Fix it. Spotted by Eric W. Biederman. Signed-off-by: Tejun Heo Cc: Eric W. Biederman Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index a0da2b0..54ca4bc 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -130,8 +130,10 @@ struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) /* look it up */ parent_dentry = dentry; + mutex_lock(&parent_dentry->d_inode->i_mutex); dentry = lookup_one_len_kern(cur->s_name, parent_dentry, strlen(cur->s_name)); + mutex_unlock(&parent_dentry->d_inode->i_mutex); dput(parent_dentry); if (IS_ERR(dentry)) { -- cgit v0.10.2 From 372e88bd1922228e0a55228f6dc8e311d1696fa0 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:29 +0900 Subject: sysfs: Move all of inode initialization into sysfs_init_inode Signed-off-by: "Eric W. Biederman" Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 54ca4bc..5a70a93 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -748,24 +748,12 @@ int sysfs_create_dir(struct kobject * kobj) return error; } -static int sysfs_count_nlink(struct sysfs_dirent *sd) -{ - struct sysfs_dirent *child; - int nr = 0; - - for (child = sd->s_children; child; child = child->s_sibling) - if (sysfs_type(child) == SYSFS_DIR) - nr++; - return nr + 2; -} - static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct dentry *ret = NULL; struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata; struct sysfs_dirent *sd; - struct bin_attribute *bin_attr; struct inode *inode; mutex_lock(&sysfs_mutex); @@ -785,31 +773,6 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, goto out_unlock; } - if (inode->i_state & I_NEW) { - /* initialize inode according to type */ - switch (sysfs_type(sd)) { - case SYSFS_DIR: - inode->i_op = &sysfs_dir_inode_operations; - inode->i_fop = &sysfs_dir_operations; - inode->i_nlink = sysfs_count_nlink(sd); - break; - case SYSFS_KOBJ_ATTR: - inode->i_size = PAGE_SIZE; - inode->i_fop = &sysfs_file_operations; - break; - case SYSFS_KOBJ_BIN_ATTR: - bin_attr = sd->s_elem.bin_attr.bin_attr; - inode->i_size = bin_attr->size; - inode->i_fop = &bin_fops; - break; - case SYSFS_KOBJ_LINK: - inode->i_op = &sysfs_symlink_inode_operations; - break; - default: - BUG(); - } - } - sysfs_instantiate(dentry, inode); sysfs_attach_dentry(sd, dentry); diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index e22db6c..200e1bf 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -122,8 +122,22 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) */ static struct lock_class_key sysfs_inode_imutex_key; +static int sysfs_count_nlink(struct sysfs_dirent *sd) +{ + struct sysfs_dirent *child; + int nr = 0; + + for (child = sd->s_children; child; child = child->s_sibling) + if (sysfs_type(child) == SYSFS_DIR) + nr++; + + return nr + 2; +} + static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) { + struct bin_attribute *bin_attr; + inode->i_blocks = 0; inode->i_mapping->a_ops = &sysfs_aops; inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; @@ -139,6 +153,37 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) set_inode_attr(inode, sd->s_iattr); } else set_default_inode_attr(inode, sd->s_mode); + + + /* initialize inode according to type */ + switch (sysfs_type(sd)) { + case SYSFS_ROOT: + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; + inc_nlink(inode); /* directory, account for "." */ + break; + case SYSFS_DIR: + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; + inode->i_nlink = sysfs_count_nlink(sd); + break; + case SYSFS_KOBJ_ATTR: + inode->i_size = PAGE_SIZE; + inode->i_fop = &sysfs_file_operations; + break; + case SYSFS_KOBJ_BIN_ATTR: + bin_attr = sd->s_elem.bin_attr.bin_attr; + inode->i_size = bin_attr->size; + inode->i_fop = &bin_fops; + break; + case SYSFS_KOBJ_LINK: + inode->i_op = &sysfs_symlink_inode_operations; + break; + default: + BUG(); + } + + unlock_new_inode(inode); } /** @@ -180,9 +225,6 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode) { BUG_ON(!dentry || dentry->d_inode); - if (inode->i_state & I_NEW) - unlock_new_inode(inode); - d_instantiate(dentry, inode); } diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 119f39d..92f407f 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -49,11 +49,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; } - inode->i_op = &sysfs_dir_inode_operations; - inode->i_fop = &sysfs_dir_operations; - inc_nlink(inode); /* directory, account for "." */ - unlock_new_inode(inode); - /* instantiate and link root dentry */ root = d_alloc_root(inode); if (!root) { -- cgit v0.10.2 From 119dd52be33dfe6285f586ab7354897fdefc7e23 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:29 +0900 Subject: sysfs: Remove sysfs_instantiate Now that sysfs_get_inode is dropping the inode lock we no longer have a need from sysfs_instantiate. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 5a70a93..739dda1 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -773,7 +773,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, goto out_unlock; } - sysfs_instantiate(dentry, inode); + d_instantiate(dentry, inode); sysfs_attach_dentry(sd, dentry); out_unlock: diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 200e1bf..0d706a8 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -211,23 +211,6 @@ struct inode * sysfs_get_inode(struct sysfs_dirent *sd) return inode; } -/** - * sysfs_instantiate - instantiate dentry - * @dentry: dentry to be instantiated - * @inode: inode associated with @sd - * - * Unlock @inode if locked and instantiate @dentry with @inode. - * - * LOCKING: - * None. - */ -void sysfs_instantiate(struct dentry *dentry, struct inode *inode) -{ - BUG_ON(!dentry || dentry->d_inode); - - d_instantiate(dentry, inode); -} - int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) { struct sysfs_addrm_cxt acxt; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 0436754..8a0aea1 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -69,7 +69,6 @@ extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, extern void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd); -extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode); extern void release_sysfs_dirent(struct sysfs_dirent * sd); extern struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, -- cgit v0.10.2 From 0333cd8a3f4249fde2c50929a6eac35245fc685b Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:29 +0900 Subject: sysfs: Use kill_anon_super Since sysfs no longer stores fs directory information in the dcache on a permanent basis kill_litter_super it is inappropriate and actively wrong. It will decrement the count on all dentries left in the dcache before trying to free them. At the moment this is not biting us only because we never unmount sysfs. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 92f407f..ac76256 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -71,7 +71,7 @@ static int sysfs_get_sb(struct file_system_type *fs_type, static struct file_system_type sysfs_fs_type = { .name = "sysfs", .get_sb = sysfs_get_sb, - .kill_sb = kill_litter_super, + .kill_sb = kill_anon_super, }; int __init sysfs_init(void) -- cgit v0.10.2 From 7d0c7d676cc066413e1583b5af9fba8011972d41 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:30 +0900 Subject: sysfs: Make sysfs_mount static This patch modifies the users of sysfs_mount to use sysfs_root instead (which is what they are looking for). It then makes sysfs_mount static to keep people from using it by accident. The net result is slightly faster and cleaner code. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 739dda1..7f4abe1 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -737,10 +737,8 @@ int sysfs_create_dir(struct kobject * kobj) if (kobj->parent) parent_sd = kobj->parent->sd; - else if (sysfs_mount && sysfs_mount->mnt_sb) - parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata; else - return -EFAULT; + parent_sd = &sysfs_root; error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd); if (!error) diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index ac76256..8989cbb 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -14,7 +14,7 @@ /* Random magic number */ #define SYSFS_MAGIC 0x62656572 -struct vfsmount *sysfs_mount; +static struct vfsmount *sysfs_mount; struct super_block * sysfs_sb = NULL; struct kmem_cache *sysfs_dir_cachep; diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index a6b13f1..8ad38bc 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -60,10 +60,9 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char BUG_ON(!name); - if (!kobj) { - if (sysfs_mount && sysfs_mount->mnt_sb) - parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata; - } else + if (!kobj) + parent_sd = &sysfs_root; + else parent_sd = kobj->sd; error = -EFAULT; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 8a0aea1..77253aa 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -51,7 +51,6 @@ struct sysfs_addrm_cxt { int cnt; }; -extern struct vfsmount * sysfs_mount; extern struct sysfs_dirent sysfs_root; extern struct kmem_cache *sysfs_dir_cachep; -- cgit v0.10.2 From 94777e09180b6249d455baa2dbe34cf630e0c033 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:30 +0900 Subject: sysfs: In sysfs_lookup don't open code sysfs_find_dirent This is a small cleanup patch that makes the code just a little bit cleaner. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 7f4abe1..b72b42e 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -756,9 +756,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, mutex_lock(&sysfs_mutex); - for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) - if (sysfs_type(sd) && !strcmp(sd->s_name, dentry->d_name.name)) - break; + sd = sysfs_find_dirent(parent_sd, dentry->d_name.name); /* no such entry */ if (!sd) -- cgit v0.10.2 From 3efa65b92d832873ece62b42a4268c2515943977 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:30 +0900 Subject: sysfs: Simplify readdir. At some point someone wrote sysfs_readdir to insert a cursor into the list of sysfs_dirents to ensure that sysfs_readdir would restart properly. That works but it is complex code and tends to be expensive. The same effect can be achieved by keeping the sysfs_dirents in inode order and using the inode number as the f_pos. Then when we restart we just have to find the first dirent whose inode number is equal or greater then the last sysfs_dirent we attempted to return. Removing the sysfs directory cursor also allows the remove of all of the mysterious checks for sysfs_type(sd) != 0. Which were nonbovious checks to see if a cursor was in a directory list. tj: offset marker for EOF is changed from UINT_MAX to INT_MAX to avoid overflow in case offset is 32bit. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index b72b42e..953e843 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -33,10 +33,20 @@ static DEFINE_IDA(sysfs_ino_ida); static void sysfs_link_sibling(struct sysfs_dirent *sd) { struct sysfs_dirent *parent_sd = sd->s_parent; + struct sysfs_dirent **pos; BUG_ON(sd->s_sibling); - sd->s_sibling = parent_sd->s_children; - parent_sd->s_children = sd; + + /* Store directory entries in order by ino. This allows + * readdir to properly restart without having to add a + * cursor into the s_children list. + */ + for (pos = &parent_sd->s_children; *pos; pos = &(*pos)->s_sibling) { + if (sd->s_ino < (*pos)->s_ino) + break; + } + sd->s_sibling = *pos; + *pos = sd; } /** @@ -659,7 +669,7 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, struct sysfs_dirent *sd; for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) - if (sysfs_type(sd) && !strcmp(sd->s_name, name)) + if (!strcmp(sd->s_name, name)) return sd; return NULL; } @@ -811,7 +821,7 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) while (*pos) { struct sysfs_dirent *sd = *pos; - if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) + if (sysfs_type(sd) != SYSFS_DIR) sysfs_remove_one(&acxt, sd); else pos = &(*pos)->s_sibling; @@ -976,37 +986,6 @@ again: return error; } -static int sysfs_dir_open(struct inode *inode, struct file *file) -{ - struct dentry * dentry = file->f_path.dentry; - struct sysfs_dirent * parent_sd = dentry->d_fsdata; - struct sysfs_dirent * sd; - - sd = sysfs_new_dirent("_DIR_", 0, 0); - if (sd) { - mutex_lock(&sysfs_mutex); - sd->s_parent = sysfs_get(parent_sd); - sysfs_link_sibling(sd); - mutex_unlock(&sysfs_mutex); - } - - file->private_data = sd; - return sd ? 0 : -ENOMEM; -} - -static int sysfs_dir_close(struct inode *inode, struct file *file) -{ - struct sysfs_dirent * cursor = file->private_data; - - mutex_lock(&sysfs_mutex); - sysfs_unlink_sibling(cursor); - mutex_unlock(&sysfs_mutex); - - release_sysfs_dirent(cursor); - - return 0; -} - /* Relationship between s_mode and the DT_xxx types */ static inline unsigned char dt_type(struct sysfs_dirent *sd) { @@ -1017,117 +996,51 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) { struct dentry *dentry = filp->f_path.dentry; struct sysfs_dirent * parent_sd = dentry->d_fsdata; - struct sysfs_dirent *cursor = filp->private_data; - struct sysfs_dirent **pos; + struct sysfs_dirent *pos; ino_t ino; - int i = filp->f_pos; - switch (i) { - case 0: - ino = parent_sd->s_ino; - if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) - break; + if (filp->f_pos == 0) { + ino = parent_sd->s_ino; + if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0) filp->f_pos++; - i++; - /* fallthrough */ - case 1: - if (parent_sd->s_parent) - ino = parent_sd->s_parent->s_ino; - else - ino = parent_sd->s_ino; - if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) - break; + } + if (filp->f_pos == 1) { + if (parent_sd->s_parent) + ino = parent_sd->s_parent->s_ino; + else + ino = parent_sd->s_ino; + if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0) filp->f_pos++; - i++; - /* fallthrough */ - default: - mutex_lock(&sysfs_mutex); - - pos = &parent_sd->s_children; - while (*pos != cursor) - pos = &(*pos)->s_sibling; - - /* unlink cursor */ - *pos = cursor->s_sibling; - - if (filp->f_pos == 2) - pos = &parent_sd->s_children; - - for ( ; *pos; pos = &(*pos)->s_sibling) { - struct sysfs_dirent *next = *pos; - const char * name; - int len; - - if (!sysfs_type(next)) - continue; - - name = next->s_name; - len = strlen(name); - ino = next->s_ino; - - if (filldir(dirent, name, len, filp->f_pos, ino, - dt_type(next)) < 0) - break; - - filp->f_pos++; - } + } + if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) { + mutex_lock(&sysfs_mutex); - /* put cursor back in */ - cursor->s_sibling = *pos; - *pos = cursor; + /* Skip the dentries we have already reported */ + pos = parent_sd->s_children; + while (pos && (filp->f_pos > pos->s_ino)) + pos = pos->s_sibling; - mutex_unlock(&sysfs_mutex); - } - return 0; -} + for ( ; pos; pos = pos->s_sibling) { + const char * name; + int len; -static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) -{ - struct dentry * dentry = file->f_path.dentry; + name = pos->s_name; + len = strlen(name); + filp->f_pos = ino = pos->s_ino; - switch (origin) { - case 1: - offset += file->f_pos; - case 0: - if (offset >= 0) + if (filldir(dirent, name, len, filp->f_pos, ino, + dt_type(pos)) < 0) break; - default: - return -EINVAL; - } - if (offset != file->f_pos) { - mutex_lock(&sysfs_mutex); - - file->f_pos = offset; - if (file->f_pos >= 2) { - struct sysfs_dirent *sd = dentry->d_fsdata; - struct sysfs_dirent *cursor = file->private_data; - struct sysfs_dirent **pos; - loff_t n = file->f_pos - 2; - - sysfs_unlink_sibling(cursor); - - pos = &sd->s_children; - while (n && *pos) { - struct sysfs_dirent *next = *pos; - if (sysfs_type(next)) - n--; - pos = &(*pos)->s_sibling; - } - - cursor->s_sibling = *pos; - *pos = cursor; } - + if (!pos) + filp->f_pos = INT_MAX; mutex_unlock(&sysfs_mutex); } - - return offset; + return 0; } + const struct file_operations sysfs_dir_operations = { - .open = sysfs_dir_open, - .release = sysfs_dir_close, - .llseek = sysfs_dir_lseek, .read = generic_read_dir, .readdir = sysfs_readdir, }; -- cgit v0.10.2 From 89bec09705d2033b8b765f3c3ac5093f80bd5bc4 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:30 +0900 Subject: sysfs: Rewrite sysfs_drop_dentry. Currently we find the dentry to drop by looking at sd->s_dentry. We can just as easily accomplish the same task by looking up the sysfs inode and finding all of the dentries from there, with the added bonus that we don't need to play with the sysfs_assoc_lock. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 953e843..1af963e 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -565,50 +565,49 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) * Drop dentry for @sd. @sd must have been unlinked from its * parent on entry to this function such that it can't be looked * up anymore. - * - * @sd->s_dentry which is protected with sysfs_assoc_lock points - * to the currently associated dentry but we're not holding a - * reference to it and racing with dput(). Grab dcache_lock and - * verify dentry before dropping it. If @sd->s_dentry is NULL or - * dput() beats us, no need to bother. */ static void sysfs_drop_dentry(struct sysfs_dirent *sd) { - struct dentry *dentry = NULL; struct inode *inode; + struct dentry *dentry; + + inode = ilookup(sysfs_sb, sd->s_ino); + if (!inode) + return; - /* We're not holding a reference to ->s_dentry dentry but the - * field will stay valid as long as sysfs_assoc_lock is held. + /* Drop any existing dentries associated with sd. + * + * For the dentry to be properly freed we need to grab a + * reference to the dentry under the dcache lock, unhash it, + * and then put it. The playing with the dentry count allows + * dput to immediately free the dentry if it is not in use. */ - spin_lock(&sysfs_assoc_lock); +repeat: spin_lock(&dcache_lock); - - /* drop dentry if it's there and dput() didn't kill it yet */ - if (sd->s_dentry && sd->s_dentry->d_inode) { - dentry = dget_locked(sd->s_dentry); + list_for_each_entry(dentry, &inode->i_dentry, d_alias) { + if (d_unhashed(dentry)) + continue; + dget_locked(dentry); spin_lock(&dentry->d_lock); __d_drop(dentry); spin_unlock(&dentry->d_lock); + spin_unlock(&dcache_lock); + dput(dentry); + goto repeat; } - spin_unlock(&dcache_lock); - spin_unlock(&sysfs_assoc_lock); - - dput(dentry); /* adjust nlink and update timestamp */ - inode = ilookup(sysfs_sb, sd->s_ino); - if (inode) { - mutex_lock(&inode->i_mutex); + mutex_lock(&inode->i_mutex); - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME; + drop_nlink(inode); + if (sysfs_type(sd) == SYSFS_DIR) drop_nlink(inode); - if (sysfs_type(sd) == SYSFS_DIR) - drop_nlink(inode); - mutex_unlock(&inode->i_mutex); - iput(inode); - } + mutex_unlock(&inode->i_mutex); + + iput(inode); } /** -- cgit v0.10.2 From 932ea2e374dd1ca26676297a5eccd1cdab86f7cd Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:30 +0900 Subject: sysfs: Introduce sysfs_rename_mutex Looking carefully at the rename code we have a subtle dependency that the structure of sysfs not change while we are performing a rename. If the parent directory of the object we are renaming changes while the rename is being performed nasty things could happen when we go to release our locks. So introduce a sysfs_rename_mutex to prevent this highly unlikely theoretical issue. In addition hold sysfs_rename_mutex over all calls to sysfs_get_dentry. Allowing sysfs_get_dentry to be simplified in the future. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 1af963e..9fe83d2 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -15,6 +15,7 @@ #include "sysfs.h" DEFINE_MUTEX(sysfs_mutex); +DEFINE_MUTEX(sysfs_rename_mutex); spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED; static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED; @@ -82,7 +83,7 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) * down from there looking up dentry for each step. * * LOCKING: - * Kernel thread context (may sleep) + * mutex_lock(sysfs_rename_mutex) * * RETURNS: * Pointer to found dentry on success, ERR_PTR() value on error. @@ -858,6 +859,8 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) const char *dup_name = NULL; int error; + mutex_lock(&sysfs_rename_mutex); + /* get the original dentry */ sd = kobj->sd; old_dentry = sysfs_get_dentry(sd); @@ -915,6 +918,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) kfree(dup_name); dput(old_dentry); dput(new_dentry); + mutex_unlock(&sysfs_rename_mutex); return error; } @@ -926,6 +930,7 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) struct dentry *old_dentry = NULL, *new_dentry = NULL; int error; + mutex_lock(&sysfs_rename_mutex); BUG_ON(!sd->s_parent); new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; @@ -982,6 +987,7 @@ again: dput(new_parent); dput(old_dentry); dput(new_dentry); + mutex_unlock(&sysfs_rename_mutex); return error; } diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 16f39c3..ff93c92 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -470,7 +470,9 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) if (!victim_sd) goto out; + mutex_lock(&sysfs_rename_mutex); victim = sysfs_get_dentry(victim_sd); + mutex_unlock(&sysfs_rename_mutex); if (IS_ERR(victim)) { rc = PTR_ERR(victim); victim = NULL; @@ -509,7 +511,9 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) if (!victim_sd) goto out; + mutex_lock(&sysfs_rename_mutex); victim = sysfs_get_dentry(victim_sd); + mutex_unlock(&sysfs_rename_mutex); if (IS_ERR(victim)) { rc = PTR_ERR(victim); victim = NULL; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 77253aa..179e6a2 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -90,6 +90,7 @@ extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); extern spinlock_t sysfs_assoc_lock; extern struct mutex sysfs_mutex; +extern struct mutex sysfs_rename_mutex; extern struct super_block * sysfs_sb; extern const struct file_operations sysfs_dir_operations; extern const struct file_operations sysfs_file_operations; -- cgit v0.10.2 From e0712bbfd9cb617fc3a822781c2466fb6b7ede50 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 20 Aug 2007 21:36:30 +0900 Subject: sysfs: simply sysfs_get_dentry Now that we know the sysfs tree structure cannot change under us and sysfs shadow support is dropped, sysfs_get_dentry() can be simplified greatly. It can just look up from the root and there's no need to retry on failure. Signed-off-by: Tejun Heo Cc: Eric W. Biederman Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 9fe83d2..1c3dc5d 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -78,9 +78,8 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) * @sd: sysfs_dirent of interest * * Get dentry for @sd. Dentry is looked up if currently not - * present. This function climbs sysfs_dirent tree till it - * reaches a sysfs_dirent with valid dentry attached and descends - * down from there looking up dentry for each step. + * present. This function descends from the root looking up + * dentry for each step. * * LOCKING: * mutex_lock(sysfs_rename_mutex) @@ -90,86 +89,28 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) */ struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) { - struct sysfs_dirent *cur; - struct dentry *parent_dentry, *dentry; - int i, depth; + struct dentry *dentry = dget(sysfs_sb->s_root); - /* Find the first parent which has valid s_dentry and get the - * dentry. - */ - mutex_lock(&sysfs_mutex); - restart0: - spin_lock(&sysfs_assoc_lock); - restart1: - spin_lock(&dcache_lock); - - dentry = NULL; - depth = 0; - cur = sd; - while (!cur->s_dentry || !cur->s_dentry->d_inode) { - if (cur->s_flags & SYSFS_FLAG_REMOVED) { - dentry = ERR_PTR(-ENOENT); - depth = 0; - break; - } - cur = cur->s_parent; - depth++; - } - if (!IS_ERR(dentry)) - dentry = dget_locked(cur->s_dentry); + while (dentry->d_fsdata != sd) { + struct sysfs_dirent *cur; + struct dentry *parent; - spin_unlock(&dcache_lock); - spin_unlock(&sysfs_assoc_lock); - - /* from the found dentry, look up depth times */ - while (depth--) { - /* find and get depth'th ancestor */ - for (cur = sd, i = 0; cur && i < depth; i++) + /* find the first ancestor which hasn't been looked up */ + cur = sd; + while (cur->s_parent != dentry->d_fsdata) cur = cur->s_parent; - /* This can happen if tree structure was modified due - * to move/rename. Restart. - */ - if (i != depth) { - dput(dentry); - goto restart0; - } - - sysfs_get(cur); - - mutex_unlock(&sysfs_mutex); - /* look it up */ - parent_dentry = dentry; - mutex_lock(&parent_dentry->d_inode->i_mutex); - dentry = lookup_one_len_kern(cur->s_name, parent_dentry, + parent = dentry; + mutex_lock(&parent->d_inode->i_mutex); + dentry = lookup_one_len_kern(cur->s_name, parent, strlen(cur->s_name)); - mutex_unlock(&parent_dentry->d_inode->i_mutex); - dput(parent_dentry); - - if (IS_ERR(dentry)) { - sysfs_put(cur); - return dentry; - } + mutex_unlock(&parent->d_inode->i_mutex); + dput(parent); - mutex_lock(&sysfs_mutex); - spin_lock(&sysfs_assoc_lock); - - /* This, again, can happen if tree structure has - * changed and we looked up the wrong thing. Restart. - */ - if (cur->s_dentry != dentry) { - dput(dentry); - sysfs_put(cur); - goto restart1; - } - - spin_unlock(&sysfs_assoc_lock); - - sysfs_put(cur); + if (IS_ERR(dentry)) + break; } - - mutex_unlock(&sysfs_mutex); return dentry; } -- cgit v0.10.2 From 5a26b79c426f8e55ebf7204cb138eb6b1645d4d3 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:30 +0900 Subject: sysfs: Remove s_dentry The only uses of s_dentry left are the code that maintains s_dentry and trivial users that don't actually need it. So this patch removes the s_dentry maintenance code and restructures the trivial uses to use something else. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 1c3dc5d..36b6c79 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -289,22 +289,7 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) { struct sysfs_dirent * sd = dentry->d_fsdata; - if (sd) { - /* sd->s_dentry is protected with sysfs_assoc_lock. - * This allows sysfs_drop_dentry() to dereference it. - */ - spin_lock(&sysfs_assoc_lock); - - /* The dentry might have been deleted or another - * lookup could have happened updating sd->s_dentry to - * point the new dentry. Ignore if it isn't pointing - * to this dentry. - */ - if (sd->s_dentry == dentry) - sd->s_dentry = NULL; - spin_unlock(&sysfs_assoc_lock); - sysfs_put(sd); - } + sysfs_put(sd); iput(inode); } @@ -352,9 +337,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) * @sd: target sysfs_dirent * @dentry: dentry to associate * - * Associate @sd with @dentry. This is protected by - * sysfs_assoc_lock to avoid race with sysfs_d_iput(). - * * LOCKING: * mutex_lock(sysfs_mutex) */ @@ -362,12 +344,6 @@ static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry) { dentry->d_op = &sysfs_dentry_ops; dentry->d_fsdata = sysfs_get(sd); - - /* protect sd->s_dentry against sysfs_d_iput */ - spin_lock(&sysfs_assoc_lock); - sd->s_dentry = dentry; - spin_unlock(&sysfs_assoc_lock); - d_rehash(dentry); } @@ -846,7 +822,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) /* rename */ d_add(new_dentry, NULL); - d_move(sd->s_dentry, new_dentry); + d_move(old_dentry, new_dentry); error = 0; goto out_unlock; @@ -881,7 +857,7 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) error = PTR_ERR(old_dentry); goto out_dput; } - old_parent = sd->s_parent->s_dentry; + old_parent = old_dentry->d_parent; new_parent = sysfs_get_dentry(new_parent_sd); if (IS_ERR(new_parent)) { @@ -907,7 +883,7 @@ again: } else error = 0; d_add(new_dentry, NULL); - d_move(sd->s_dentry, new_dentry); + d_move(old_dentry, new_dentry); dput(new_dentry); /* Remove from old parent's list and insert into new parent's list. */ diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 8989cbb..28bf359 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -56,7 +56,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) iput(inode); return -ENOMEM; } - sysfs_root.s_dentry = root; root->d_fsdata = &sysfs_root; sb->s_root = root; return 0; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 179e6a2..791b3ed 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -37,7 +37,6 @@ struct sysfs_dirent { unsigned int s_flags; umode_t s_mode; ino_t s_ino; - struct dentry * s_dentry; struct iattr * s_iattr; atomic_t s_event; }; -- cgit v0.10.2 From 9918f9a4817cb6241c727b434d5f8ec5564198de Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:31 +0900 Subject: sysfs: Rewrite rename in terms of sysfs dirents This patch rewrites sysfs_rename_dir to perform it's checks as much as possible on the underlying sysfs_dirents instead of the contents of the dcache. It turns out that this version is a little simpler, and a little more like the rest of the sysfs directory modification code. tj: fixed double locking of sysfs_mutex Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 36b6c79..463c5e3 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -770,7 +770,7 @@ void sysfs_remove_dir(struct kobject * kobj) int sysfs_rename_dir(struct kobject * kobj, const char *new_name) { - struct sysfs_dirent *sd; + struct sysfs_dirent *sd = kobj->sd; struct dentry *parent = NULL; struct dentry *old_dentry = NULL, *new_dentry = NULL; const char *dup_name = NULL; @@ -778,63 +778,57 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) mutex_lock(&sysfs_rename_mutex); + error = 0; + if (strcmp(sd->s_name, new_name) == 0) + goto out; /* nothing to rename */ + /* get the original dentry */ - sd = kobj->sd; old_dentry = sysfs_get_dentry(sd); if (IS_ERR(old_dentry)) { error = PTR_ERR(old_dentry); - goto out_dput; + goto out; } parent = old_dentry->d_parent; /* lock parent and get dentry for new name */ mutex_lock(&parent->d_inode->i_mutex); + mutex_lock(&sysfs_mutex); - new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); - if (IS_ERR(new_dentry)) { - error = PTR_ERR(new_dentry); - goto out_unlock; - } - - error = -EINVAL; - if (old_dentry == new_dentry) + error = -EEXIST; + if (sysfs_find_dirent(sd->s_parent, new_name)) goto out_unlock; - error = -EEXIST; - if (new_dentry->d_inode) + error = -ENOMEM; + new_dentry = d_alloc_name(parent, new_name); + if (!new_dentry) goto out_unlock; /* rename kobject and sysfs_dirent */ error = -ENOMEM; new_name = dup_name = kstrdup(new_name, GFP_KERNEL); if (!new_name) - goto out_drop; + goto out_unlock; error = kobject_set_name(kobj, "%s", new_name); if (error) - goto out_drop; + goto out_unlock; - mutex_lock(&sysfs_mutex); dup_name = sd->s_name; sd->s_name = new_name; - mutex_unlock(&sysfs_mutex); /* rename */ d_add(new_dentry, NULL); d_move(old_dentry, new_dentry); error = 0; - goto out_unlock; - - out_drop: - d_drop(new_dentry); out_unlock: + mutex_unlock(&sysfs_mutex); mutex_unlock(&parent->d_inode->i_mutex); - out_dput: kfree(dup_name); dput(old_dentry); dput(new_dentry); + out: mutex_unlock(&sysfs_rename_mutex); return error; } -- cgit v0.10.2 From 45aaae9c51d768d5a8fd53fb372b1eb714f37691 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 20 Aug 2007 21:36:31 +0900 Subject: sysfs: Rewrite sysfs_move_dir in terms of sysfs dirents This patch rewrites sysfs_move_dir to perform it's checks as much as possible on the underlying sysfs_dirents instead of the contents of the dcache, making sysfs_move_dir more like the rest of the sysfs directory modification code. Signed-off-by: Eric W. Biederman Signed-off-by: Tejun Heo Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 463c5e3..da4bb66 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -845,56 +845,58 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) BUG_ON(!sd->s_parent); new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; + error = 0; + if (sd->s_parent == new_parent_sd) + goto out; /* nothing to move */ + /* get dentries */ old_dentry = sysfs_get_dentry(sd); if (IS_ERR(old_dentry)) { error = PTR_ERR(old_dentry); - goto out_dput; + goto out; } old_parent = old_dentry->d_parent; new_parent = sysfs_get_dentry(new_parent_sd); if (IS_ERR(new_parent)) { error = PTR_ERR(new_parent); - goto out_dput; + goto out; } - if (old_parent->d_inode == new_parent->d_inode) { - error = 0; - goto out_dput; /* nothing to move */ - } again: mutex_lock(&old_parent->d_inode->i_mutex); if (!mutex_trylock(&new_parent->d_inode->i_mutex)) { mutex_unlock(&old_parent->d_inode->i_mutex); goto again; } + mutex_lock(&sysfs_mutex); - new_dentry = lookup_one_len(kobject_name(kobj), new_parent, strlen(kobject_name(kobj))); - if (IS_ERR(new_dentry)) { - error = PTR_ERR(new_dentry); + error = -EEXIST; + if (sysfs_find_dirent(new_parent_sd, sd->s_name)) goto out_unlock; - } else - error = 0; + + error = -ENOMEM; + new_dentry = d_alloc_name(new_parent, sd->s_name); + if (!new_dentry) + goto out_unlock; + + error = 0; d_add(new_dentry, NULL); d_move(old_dentry, new_dentry); dput(new_dentry); /* Remove from old parent's list and insert into new parent's list. */ - mutex_lock(&sysfs_mutex); - sysfs_unlink_sibling(sd); sysfs_get(new_parent_sd); sysfs_put(sd->s_parent); sd->s_parent = new_parent_sd; sysfs_link_sibling(sd); - mutex_unlock(&sysfs_mutex); - out_unlock: + mutex_unlock(&sysfs_mutex); mutex_unlock(&new_parent->d_inode->i_mutex); mutex_unlock(&old_parent->d_inode->i_mutex); - out_dput: + out: dput(new_parent); dput(old_dentry); dput(new_dentry); -- cgit v0.10.2 From dc8c85871c9728c5fddca6854a191fd41eb9438c Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 15 Aug 2007 12:25:38 +0200 Subject: PTY: add kernel parameter to overwrite legacy pty count Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a57c1f2..bdddd3c 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1430,6 +1430,10 @@ and is between 256 and 4096 characters. It is defined in the file pt. [PARIDE] See Documentation/paride.txt. + pty.legacy_count= + [KNL] Number of legacy pty's. Overwrites compiled-in + default number. + quiet [KNL] Disable most log messages r128= [HW,DRM] diff --git a/drivers/char/pty.c b/drivers/char/pty.c index de14aea..73de771 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -248,14 +248,19 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file, return -ENOIOCTLCMD; } +static int legacy_count = CONFIG_LEGACY_PTY_COUNT; +module_param(legacy_count, int, 0); + static void __init legacy_pty_init(void) { + if (legacy_count <= 0) + return; - pty_driver = alloc_tty_driver(NR_PTYS); + pty_driver = alloc_tty_driver(legacy_count); if (!pty_driver) panic("Couldn't allocate pty driver"); - pty_slave_driver = alloc_tty_driver(NR_PTYS); + pty_slave_driver = alloc_tty_driver(legacy_count); if (!pty_slave_driver) panic("Couldn't allocate pty slave driver"); diff --git a/include/linux/tty.h b/include/linux/tty.h index 6570719..60478f6 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -21,7 +21,6 @@ * (Note: the *_driver.minor_start values 1, 64, 128, 192 are * hardcoded at present.) */ -#define NR_PTYS CONFIG_LEGACY_PTY_COUNT /* Number of legacy ptys */ #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ #define NR_LDISCS 17 -- cgit v0.10.2 From 5c3e8964ce87477a12e3e9edc3742156a3929a74 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 Sep 2007 02:53:13 -0700 Subject: sysfs: spit a warning to users when they try to create a duplicate sysfs file We want to let people know when we create a duplicate sysfs file, as they need to fix up their code. Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index da4bb66..5d95aa8 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -428,8 +428,12 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, */ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) { - if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) + if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) { + printk(KERN_WARNING "sysfs: duplicate filename '%s' " + "can not be created\n", sd->s_name); + WARN_ON(1); return -EEXIST; + } sd->s_parent = sysfs_get(acxt->parent_sd); -- cgit v0.10.2 From 181b2e4be1603ce3ccace8322047a548f29f4b20 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:09 +0900 Subject: sysfs: fix comments of sysfs_add/remove_one() sysfs_add/remove_one() now link and unlink the target dirent into and from the children list. Update comments accordingly. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 5d95aa8..fc615ee 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -410,10 +410,8 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, * @sd: sysfs_dirent to be added * * Get @acxt->parent_sd and set sd->s_parent to it and increment - * nlink of parent inode if @sd is a directory. @sd is NOT - * linked into the children list of the parent. The caller - * should invoke sysfs_link_sibling() after this function - * completes if @sd needs to be on the children list. + * nlink of parent inode if @sd is a directory and link into the + * children list of the parent. * * This function should be called between calls to * sysfs_addrm_start() and sysfs_addrm_finish() and should be @@ -453,9 +451,7 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) * @sd: sysfs_dirent to be added * * Mark @sd removed and drop nlink of parent inode if @sd is a - * directory. @sd is NOT unlinked from the children list of the - * parent. The caller is repsonsible for removing @sd from the - * children list before calling this function. + * directory. @sd is unlinked from the children list. * * This function should be called between calls to * sysfs_addrm_start() and sysfs_addrm_finish() and should be -- cgit v0.10.2 From f88123eaf953f13a0c597dde54745d28f81236de Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:10 +0900 Subject: sysfs: fix sysfs_chmod_file() such that it updates sd->s_mode too sysfs_chmod_file() looked and updated only inode of the target file. Dentry and inode are reclaimable and the update mode data will go away when the inode is reclaimed. This patch makes sysfs_chmod_file() update sd->s_mode too such that the change is permanent. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index ff93c92..9fdf8da 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -521,10 +521,19 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) } inode = victim->d_inode; + mutex_lock(&inode->i_mutex); + newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; rc = notify_change(victim, &newattrs); + + if (rc == 0) { + mutex_lock(&sysfs_mutex); + victim_sd->s_mode = newattrs.ia_mode; + mutex_unlock(&sysfs_mutex); + } + mutex_unlock(&inode->i_mutex); out: dput(victim); -- cgit v0.10.2 From 59f69015684b3de7b9472be9a81b1a978f93a496 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:10 +0900 Subject: sysfs: clean up header files sysfs is about to go through major overhaul making this a pretty good opportunity to clean up (out-of-tree changes and pending patches will need regeneration anyway). Clean up headers. * Kill space between * and symbolname. * Move SYSFS_* type constants and flags into fs/sysfs/sysfs.h. They're internal to sysfs. * Reformat function prototypes and add argument symbol names. * Make dummy function definition order match that of function prototypes. * Add some comments. * Reorganize fs/sysfs/sysfs.h according to which file the declared variable or feature lives in. This patch does not introduce any behavior change. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 791b3ed..63adbec 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -1,20 +1,24 @@ +/* type-specific structures for sysfs_dirent->s_* union members */ struct sysfs_elem_dir { - struct kobject * kobj; + struct kobject *kobj; }; struct sysfs_elem_symlink { - struct sysfs_dirent * target_sd; + struct sysfs_dirent *target_sd; }; struct sysfs_elem_attr { - struct attribute * attr; + struct attribute *attr; }; struct sysfs_elem_bin_attr { - struct bin_attribute * bin_attr; + struct bin_attribute *bin_attr; }; /* + * sysfs_dirent - the building block of sysfs hierarchy. Each and + * every sysfs node is represented by single sysfs_dirent. + * * As long as s_count reference is held, the sysfs_dirent itself is * accessible. Dereferencing s_elem or any other outer entity * requires s_active reference. @@ -22,10 +26,10 @@ struct sysfs_elem_bin_attr { struct sysfs_dirent { atomic_t s_count; atomic_t s_active; - struct sysfs_dirent * s_parent; - struct sysfs_dirent * s_sibling; - struct sysfs_dirent * s_children; - const char * s_name; + struct sysfs_dirent *s_parent; + struct sysfs_dirent *s_sibling; + struct sysfs_dirent *s_children; + const char *s_name; union { struct sysfs_elem_dir dir; @@ -37,12 +41,31 @@ struct sysfs_dirent { unsigned int s_flags; umode_t s_mode; ino_t s_ino; - struct iattr * s_iattr; + struct iattr *s_iattr; atomic_t s_event; }; -#define SD_DEACTIVATED_BIAS INT_MIN +#define SD_DEACTIVATED_BIAS INT_MIN +#define SYSFS_TYPE_MASK 0x00ff +#define SYSFS_ROOT 0x0001 +#define SYSFS_DIR 0x0002 +#define SYSFS_KOBJ_ATTR 0x0004 +#define SYSFS_KOBJ_BIN_ATTR 0x0008 +#define SYSFS_KOBJ_LINK 0x0020 +#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) + +#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK +#define SYSFS_FLAG_REMOVED 0x0200 + +static inline unsigned int sysfs_type(struct sysfs_dirent *sd) +{ + return sd->s_flags & SYSFS_TYPE_MASK; +} + +/* + * Context structure to be used while adding/removing nodes. + */ struct sysfs_addrm_cxt { struct sysfs_dirent *parent_sd; struct inode *parent_inode; @@ -50,59 +73,47 @@ struct sysfs_addrm_cxt { int cnt; }; +/* + * mount.c + */ extern struct sysfs_dirent sysfs_root; +extern struct super_block *sysfs_sb; extern struct kmem_cache *sysfs_dir_cachep; -extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); -extern struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); -extern void sysfs_put_active(struct sysfs_dirent *sd); -extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); -extern void sysfs_put_active_two(struct sysfs_dirent *sd); -extern void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, - struct sysfs_dirent *parent_sd); -extern int sysfs_add_one(struct sysfs_addrm_cxt *acxt, - struct sysfs_dirent *sd); -extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, - struct sysfs_dirent *sd); -extern void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); - -extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd); - -extern void release_sysfs_dirent(struct sysfs_dirent * sd); -extern struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, - const unsigned char *name); -extern struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, - const unsigned char *name); -extern struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, - int type); - -extern int sysfs_add_file(struct sysfs_dirent *dir_sd, - const struct attribute *attr, int type); -extern int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); -extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name); - -extern int sysfs_create_subdir(struct kobject *kobj, const char *name, - struct sysfs_dirent **p_sd); -extern void sysfs_remove_subdir(struct sysfs_dirent *sd); - -extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); - -extern spinlock_t sysfs_assoc_lock; +/* + * dir.c + */ extern struct mutex sysfs_mutex; extern struct mutex sysfs_rename_mutex; -extern struct super_block * sysfs_sb; +extern spinlock_t sysfs_assoc_lock; + extern const struct file_operations sysfs_dir_operations; -extern const struct file_operations sysfs_file_operations; -extern const struct file_operations bin_fops; extern const struct inode_operations sysfs_dir_inode_operations; -extern const struct inode_operations sysfs_symlink_inode_operations; -static inline unsigned int sysfs_type(struct sysfs_dirent *sd) -{ - return sd->s_flags & SYSFS_TYPE_MASK; -} - -static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd) +struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd); +struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); +void sysfs_put_active(struct sysfs_dirent *sd); +struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); +void sysfs_put_active_two(struct sysfs_dirent *sd); +void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, + struct sysfs_dirent *parent_sd); +int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); +void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); +void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); + +struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, + const unsigned char *name); +struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, + const unsigned char *name); +struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type); + +void release_sysfs_dirent(struct sysfs_dirent *sd); + +int sysfs_create_subdir(struct kobject *kobj, const char *name, + struct sysfs_dirent **p_sd); +void sysfs_remove_subdir(struct sysfs_dirent *sd); + +static inline struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd) { if (sd) { WARN_ON(!atomic_read(&sd->s_count)); @@ -111,8 +122,33 @@ static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd) return sd; } -static inline void sysfs_put(struct sysfs_dirent * sd) +static inline void sysfs_put(struct sysfs_dirent *sd) { if (sd && atomic_dec_and_test(&sd->s_count)) release_sysfs_dirent(sd); } + +/* + * inode.c + */ +struct inode *sysfs_get_inode(struct sysfs_dirent *sd); +int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); +int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); + +/* + * file.c + */ +extern const struct file_operations sysfs_file_operations; + +int sysfs_add_file(struct sysfs_dirent *dir_sd, + const struct attribute *attr, int type); + +/* + * bin.c + */ +extern const struct file_operations bin_fops; + +/* + * symlink.c + */ +extern const struct inode_operations sysfs_symlink_inode_operations; diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index c16e4c5..b393bb4 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -23,14 +23,14 @@ struct module; * until the tree gets cleaned up fully. */ struct attribute { - const char * name; - struct module * owner; + const char *name; + struct module *owner; mode_t mode; }; struct attribute_group { - const char * name; - struct attribute ** attrs; + const char *name; + struct attribute **attrs; }; @@ -74,65 +74,43 @@ struct sysfs_ops { ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t); }; -#define SYSFS_TYPE_MASK 0x00ff -#define SYSFS_ROOT 0x0001 -#define SYSFS_DIR 0x0002 -#define SYSFS_KOBJ_ATTR 0x0004 -#define SYSFS_KOBJ_BIN_ATTR 0x0008 -#define SYSFS_KOBJ_LINK 0x0020 -#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) - -#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK -#define SYSFS_FLAG_REMOVED 0x0100 - #ifdef CONFIG_SYSFS -extern int sysfs_schedule_callback(struct kobject *kobj, - void (*func)(void *), void *data, struct module *owner); - -extern int __must_check -sysfs_create_dir(struct kobject *); - -extern void -sysfs_remove_dir(struct kobject *); - -extern int __must_check -sysfs_rename_dir(struct kobject *kobj, const char *new_name); - -extern int __must_check -sysfs_move_dir(struct kobject *, struct kobject *); - -extern int __must_check -sysfs_create_file(struct kobject *, const struct attribute *); - -extern int __must_check -sysfs_update_file(struct kobject *, const struct attribute *); +int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), + void *data, struct module *owner); -extern int __must_check -sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode); +int __must_check sysfs_create_dir(struct kobject *kobj); +void sysfs_remove_dir(struct kobject *kobj); +int __must_check sysfs_rename_dir(struct kobject *kobj, const char *new_name); +int __must_check sysfs_move_dir(struct kobject *kobj, + struct kobject *new_parent_kobj); -extern void -sysfs_remove_file(struct kobject *, const struct attribute *); - -extern int __must_check -sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name); - -extern void -sysfs_remove_link(struct kobject *, const char * name); +int __must_check sysfs_create_file(struct kobject *kobj, + const struct attribute *attr); +int __must_check sysfs_update_file(struct kobject *kobj, + const struct attribute *attr); +int __must_check sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, + mode_t mode); +void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr); int __must_check sysfs_create_bin_file(struct kobject *kobj, - struct bin_attribute *attr); + struct bin_attribute *attr); void sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr); -int __must_check sysfs_create_group(struct kobject *, - const struct attribute_group *); -void sysfs_remove_group(struct kobject *, const struct attribute_group *); +int __must_check sysfs_create_link(struct kobject *kobj, struct kobject *target, + const char *name); +void sysfs_remove_link(struct kobject *kobj, const char *name); + +int __must_check sysfs_create_group(struct kobject *kobj, + const struct attribute_group *grp); +void sysfs_remove_group(struct kobject *kobj, + const struct attribute_group *grp); int sysfs_add_file_to_group(struct kobject *kobj, - const struct attribute *attr, const char *group); + const struct attribute *attr, const char *group); void sysfs_remove_file_from_group(struct kobject *kobj, - const struct attribute *attr, const char *group); + const struct attribute *attr, const char *group); -void sysfs_notify(struct kobject * k, char *dir, char *attr); +void sysfs_notify(struct kobject *kobj, char *dir, char *attr); extern int __must_check sysfs_init(void); @@ -144,72 +122,81 @@ static inline int sysfs_schedule_callback(struct kobject *kobj, return -ENOSYS; } -static inline int sysfs_create_dir(struct kobject * kobj) +static inline int sysfs_create_dir(struct kobject *kobj) { return 0; } -static inline void sysfs_remove_dir(struct kobject * k) +static inline void sysfs_remove_dir(struct kobject *kobj) { ; } -static inline int sysfs_rename_dir(struct kobject * kobj, const char *new_name) +static inline int sysfs_rename_dir(struct kobject *kobj, const char *new_name) { return 0; } -static inline int sysfs_move_dir(struct kobject * k, struct kobject * new_parent) +static inline int sysfs_move_dir(struct kobject *kobj, + struct kobject *new_parent_kobj) { return 0; } -static inline int sysfs_create_file(struct kobject * k, const struct attribute * a) +static inline int sysfs_create_file(struct kobject *kobj, + const struct attribute *attr) { return 0; } -static inline int sysfs_update_file(struct kobject * k, const struct attribute * a) +static inline int sysfs_update_file(struct kobject *kobj, + const struct attribute *attr) { return 0; } -static inline int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) +static inline int sysfs_chmod_file(struct kobject *kobj, + struct attribute *attr, mode_t mode) { return 0; } -static inline void sysfs_remove_file(struct kobject * k, const struct attribute * a) +static inline void sysfs_remove_file(struct kobject *kobj, + const struct attribute *attr) { ; } -static inline int sysfs_create_link(struct kobject * k, struct kobject * t, const char * n) +static inline int sysfs_create_bin_file(struct kobject *kobj, + struct bin_attribute *attr) { return 0; } -static inline void sysfs_remove_link(struct kobject * k, const char * name) +static inline int sysfs_remove_bin_file(struct kobject *kobj, + struct bin_attribute *attr) { - ; + return 0; } - -static inline int sysfs_create_bin_file(struct kobject * k, struct bin_attribute * a) +static inline int sysfs_create_link(struct kobject *kobj, + struct kobject *target, const char *name) { return 0; } -static inline int sysfs_remove_bin_file(struct kobject * k, struct bin_attribute * a) +static inline void sysfs_remove_link(struct kobject *kobj, const char *name) { - return 0; + ; } -static inline int sysfs_create_group(struct kobject * k, const struct attribute_group *g) +static inline int sysfs_create_group(struct kobject *kobj, + const struct attribute_group *grp) { return 0; } -static inline void sysfs_remove_group(struct kobject * k, const struct attribute_group * g) +static inline void sysfs_remove_group(struct kobject *kobj, + const struct attribute_group *grp) { ; } @@ -225,7 +212,7 @@ static inline void sysfs_remove_file_from_group(struct kobject *kobj, { } -static inline void sysfs_notify(struct kobject * k, char *dir, char *attr) +static inline void sysfs_notify(struct kobject *kobj, char *dir, char *attr) { } -- cgit v0.10.2 From 5a7ad7f044941316dc98eda2a087a12a7a50649d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:10 +0900 Subject: sysfs: kill sysfs_update_file() sysfs_update_file() depends on inode->i_mtime but sysfs iondes are now reclaimable making the reported modification time unreliable. There's only one user (pci hotplug) of this notification mechanism and it reportedly isn't utilized from userland. Kill sysfs_update_file(). Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index bd433ef..f0eba53 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -694,66 +694,6 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, if ((slot == NULL) || (info == NULL)) return -ENODEV; - /* - * check all fields in the info structure, and update timestamps - * for the files referring to the fields that have now changed. - */ - if ((has_power_file(slot) == 0) && - (slot->info->power_status != info->power_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_power.attr); - if (retval) - return retval; - } - - if ((has_attention_file(slot) == 0) && - (slot->info->attention_status != info->attention_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_attention.attr); - if (retval) - return retval; - } - - if ((has_latch_file(slot) == 0) && - (slot->info->latch_status != info->latch_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_latch.attr); - if (retval) - return retval; - } - - if ((has_adapter_file(slot) == 0) && - (slot->info->adapter_status != info->adapter_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_presence.attr); - if (retval) - return retval; - } - - if ((has_address_file(slot) == 0) && - (slot->info->address != info->address)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_address.attr); - if (retval) - return retval; - } - - if ((has_max_bus_speed_file(slot) == 0) && - (slot->info->max_bus_speed != info->max_bus_speed)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_max_bus_speed.attr); - if (retval) - return retval; - } - - if ((has_cur_bus_speed_file(slot) == 0) && - (slot->info->cur_bus_speed != info->cur_bus_speed)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_cur_bus_speed.attr); - if (retval) - return retval; - } - memcpy (slot->info, info, sizeof (struct hotplug_slot_info)); return 0; diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 9fdf8da..61a8c19 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -3,7 +3,6 @@ */ #include -#include #include #include #include @@ -453,44 +452,6 @@ int sysfs_add_file_to_group(struct kobject *kobj, } EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); - -/** - * sysfs_update_file - update the modified timestamp on an object attribute. - * @kobj: object we're acting for. - * @attr: attribute descriptor. - */ -int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) -{ - struct sysfs_dirent *victim_sd = NULL; - struct dentry *victim = NULL; - int rc; - - rc = -ENOENT; - victim_sd = sysfs_get_dirent(kobj->sd, attr->name); - if (!victim_sd) - goto out; - - mutex_lock(&sysfs_rename_mutex); - victim = sysfs_get_dentry(victim_sd); - mutex_unlock(&sysfs_rename_mutex); - if (IS_ERR(victim)) { - rc = PTR_ERR(victim); - victim = NULL; - goto out; - } - - mutex_lock(&victim->d_inode->i_mutex); - victim->d_inode->i_mtime = CURRENT_TIME; - fsnotify_modify(victim); - mutex_unlock(&victim->d_inode->i_mutex); - rc = 0; - out: - dput(victim); - sysfs_put(victim_sd); - return rc; -} - - /** * sysfs_chmod_file - update the modified mode value on an object attribute. * @kobj: object we're acting for. @@ -641,4 +602,3 @@ EXPORT_SYMBOL_GPL(sysfs_schedule_callback); EXPORT_SYMBOL_GPL(sysfs_create_file); EXPORT_SYMBOL_GPL(sysfs_remove_file); -EXPORT_SYMBOL_GPL(sysfs_update_file); diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index b393bb4..db5dd24 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -87,8 +87,6 @@ int __must_check sysfs_move_dir(struct kobject *kobj, int __must_check sysfs_create_file(struct kobject *kobj, const struct attribute *attr); -int __must_check sysfs_update_file(struct kobject *kobj, - const struct attribute *attr); int __must_check sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode); void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr); @@ -149,11 +147,6 @@ static inline int sysfs_create_file(struct kobject *kobj, return 0; } -static inline int sysfs_update_file(struct kobject *kobj, - const struct attribute *attr) -{ - return 0; -} static inline int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) { -- cgit v0.10.2 From b13dc89c5a5bd5e34aadb44c0fb7e870959dcd06 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:10 +0900 Subject: sysfs: reposition sysfs_dirent->s_mode. Move s_mode downward such that it's side-by-side with s_iattr which is used for the same thing. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 63adbec..6cf61c8 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -39,8 +39,8 @@ struct sysfs_dirent { } s_elem; unsigned int s_flags; - umode_t s_mode; ino_t s_ino; + umode_t s_mode; struct iattr *s_iattr; atomic_t s_event; }; -- cgit v0.10.2 From b05f0548dabd20433f8c201a0307103721d6a18b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:10 +0900 Subject: sysfs: kill unnecessary sysfs_get() in open paths There's no reason to get an extra reference to sysfs_dirent for an open file. Open file has a reference to the dentry which in turn has a reference to sysfs_dirent. This is fairly obvious as otherwise open itself won't be able to access the sysfs_dirent. Kill the extra sysfs_get() and matching sysfs_put(). Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index a819a7e..e93fe5e 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -193,9 +193,8 @@ static int open(struct inode * inode, struct file * file) mutex_init(&bb->mutex); file->private_data = bb; - /* open succeeded, put active reference and pin attr_sd */ + /* open succeeded, put active reference */ sysfs_put_active(attr_sd); - sysfs_get(attr_sd); return 0; err_out: @@ -211,7 +210,6 @@ static int release(struct inode * inode, struct file * file) if (bb->mmapped) sysfs_put_active_two(attr_sd); - sysfs_put(attr_sd); kfree(bb->buffer); kfree(bb); return 0; diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 61a8c19..73333dc 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -298,9 +298,8 @@ static int sysfs_open_file(struct inode *inode, struct file *file) buffer->ops = ops; file->private_data = buffer; - /* open succeeded, put active references and pin attr_sd */ + /* open succeeded, put active references */ sysfs_put_active_two(attr_sd); - sysfs_get(attr_sd); return 0; err_out: @@ -310,11 +309,8 @@ static int sysfs_open_file(struct inode *inode, struct file *file) static int sysfs_release(struct inode * inode, struct file * filp) { - struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; struct sysfs_buffer *buffer = filp->private_data; - sysfs_put(attr_sd); - if (buffer) { if (buffer->page) free_page((unsigned long)buffer->page); -- cgit v0.10.2 From 50ab1a72863b1ad4b117862bc52610f8d4535609 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:10 +0900 Subject: sysfs: kill unnecessary NULL pointer check in sysfs_release() In sysfs_release(), sysfs_buffer pointed to by filp->private_data is guaranteed to exist. Kill the unnecessary NULL check. This also makes the code more consistent with the counterpart in fs/sysfs/bin.c. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 73333dc..8f1ebd8 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -311,11 +311,10 @@ static int sysfs_release(struct inode * inode, struct file * filp) { struct sysfs_buffer *buffer = filp->private_data; - if (buffer) { - if (buffer->page) - free_page((unsigned long)buffer->page); - kfree(buffer); - } + if (buffer->page) + free_page((unsigned long)buffer->page); + kfree(buffer); + return 0; } -- cgit v0.10.2 From 078ce6409ca54d5fc6eb7d2147cd6efc3eb09078 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:10 +0900 Subject: sysfs: make bin attr open get active reference of parent too All bin attr operations require active references of itself and its parent. There's no reason to allow open when its parent has been deactivated and allowing it is inconsistent with regular sysfs file. Use sysfs_get_active_two() in bin attribute open function. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index e93fe5e..9c8f882 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -171,8 +171,8 @@ static int open(struct inode * inode, struct file * file) struct bin_buffer *bb = NULL; int error; - /* need attr_sd for attr */ - if (!sysfs_get_active(attr_sd)) + /* binary file operations requires both @sd and its parent */ + if (!sysfs_get_active_two(attr_sd)) return -ENODEV; error = -EACCES; @@ -193,12 +193,12 @@ static int open(struct inode * inode, struct file * file) mutex_init(&bb->mutex); file->private_data = bb; - /* open succeeded, put active reference */ - sysfs_put_active(attr_sd); + /* open succeeded, put active references */ + sysfs_put_active_two(attr_sd); return 0; err_out: - sysfs_put_active(attr_sd); + sysfs_put_active_two(attr_sd); kfree(bb); return error; } -- cgit v0.10.2 From b1fc3d6144d56360d1373b01c7881826f558b6cd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:11 +0900 Subject: sysfs: make s_elem an anonymous union Make s_elem an anonymous union. Prefixing with s_elem makes things needlessly longer without any advantage. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 9c8f882..247ea19 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -30,8 +30,8 @@ static int fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) { struct sysfs_dirent *attr_sd = dentry->d_fsdata; - struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; int rc; /* need attr_sd for attr, its parent for kobj */ @@ -87,8 +87,8 @@ static int flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) { struct sysfs_dirent *attr_sd = dentry->d_fsdata; - struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; int rc; /* need attr_sd for attr, its parent for kobj */ @@ -140,8 +140,8 @@ static int mmap(struct file *file, struct vm_area_struct *vma) { struct bin_buffer *bb = file->private_data; struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; - struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; int rc; mutex_lock(&bb->mutex); @@ -167,7 +167,7 @@ static int mmap(struct file *file, struct vm_area_struct *vma) static int open(struct inode * inode, struct file * file) { struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; - struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; + struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; struct bin_buffer *bb = NULL; int error; diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index fc615ee..6ee76a8 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -273,7 +273,7 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) parent_sd = sd->s_parent; if (sysfs_type(sd) == SYSFS_KOBJ_LINK) - sysfs_put(sd->s_elem.symlink.target_sd); + sysfs_put(sd->s_symlink.target_sd); if (sysfs_type(sd) & SYSFS_COPY_NAME) kfree(sd->s_name); kfree(sd->s_iattr); @@ -630,7 +630,7 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, sd = sysfs_new_dirent(name, mode, SYSFS_DIR); if (!sd) return -ENOMEM; - sd->s_elem.dir.kobj = kobj; + sd->s_dir.kobj = kobj; /* link in */ sysfs_addrm_start(&acxt, parent_sd); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 8f1ebd8..3c91a57 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -73,7 +73,7 @@ struct sysfs_buffer { static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) { struct sysfs_dirent *attr_sd = dentry->d_fsdata; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; struct sysfs_ops * ops = buffer->ops; int ret = 0; ssize_t count; @@ -88,7 +88,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer return -ENODEV; buffer->event = atomic_read(&attr_sd->s_event); - count = ops->show(kobj, attr_sd->s_elem.attr.attr, buffer->page); + count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page); sysfs_put_active_two(attr_sd); @@ -188,7 +188,7 @@ static int flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count) { struct sysfs_dirent *attr_sd = dentry->d_fsdata; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; struct sysfs_ops * ops = buffer->ops; int rc; @@ -196,7 +196,7 @@ flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t if (!sysfs_get_active_two(attr_sd)) return -ENODEV; - rc = ops->store(kobj, attr_sd->s_elem.attr.attr, buffer->page, count); + rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count); sysfs_put_active_two(attr_sd); @@ -240,7 +240,7 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t static int sysfs_open_file(struct inode *inode, struct file *file) { struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; struct sysfs_buffer * buffer; struct sysfs_ops * ops = NULL; int error; @@ -336,7 +336,7 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait) { struct sysfs_buffer * buffer = filp->private_data; struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; - struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; + struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; /* need parent for the kobj, grab both */ if (!sysfs_get_active_two(attr_sd)) @@ -396,7 +396,7 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, sd = sysfs_new_dirent(attr->name, mode, type); if (!sd) return -ENOMEM; - sd->s_elem.attr.attr = (void *)attr; + sd->s_attr.attr = (void *)attr; sysfs_addrm_start(&acxt, dir_sd); rc = sysfs_add_one(&acxt, sd); diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 0d706a8..b6ac4e6 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -172,7 +172,7 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) inode->i_fop = &sysfs_file_operations; break; case SYSFS_KOBJ_BIN_ATTR: - bin_attr = sd->s_elem.bin_attr.bin_attr; + bin_attr = sd->s_bin_attr.bin_attr; inode->i_size = bin_attr->size; inode->i_fop = &bin_fops; break; diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 8ad38bc..ffa82e9 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -86,7 +86,7 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char if (!sd) goto out_put; - sd->s_elem.symlink.target_sd = target_sd; + sd->s_symlink.target_sd = target_sd; target_sd = NULL; /* reference is now owned by the symlink */ sysfs_addrm_start(&acxt, parent_sd); @@ -142,7 +142,7 @@ static int sysfs_getlink(struct dentry *dentry, char * path) { struct sysfs_dirent *sd = dentry->d_fsdata; struct sysfs_dirent *parent_sd = sd->s_parent; - struct sysfs_dirent *target_sd = sd->s_elem.symlink.target_sd; + struct sysfs_dirent *target_sd = sd->s_symlink.target_sd; int error; mutex_lock(&sysfs_mutex); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 6cf61c8..2a68bfa 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -32,11 +32,11 @@ struct sysfs_dirent { const char *s_name; union { - struct sysfs_elem_dir dir; - struct sysfs_elem_symlink symlink; - struct sysfs_elem_attr attr; - struct sysfs_elem_bin_attr bin_attr; - } s_elem; + struct sysfs_elem_dir s_dir; + struct sysfs_elem_symlink s_symlink; + struct sysfs_elem_attr s_attr; + struct sysfs_elem_bin_attr s_bin_attr; + }; unsigned int s_flags; ino_t s_ino; -- cgit v0.10.2 From d6b4fd2faeb9ddf55ce09cf90b88981e579ee010 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:11 +0900 Subject: sysfs: open code sysfs_attach_dentry() sysfs_attach_dentry() now has only one caller and isn't doing much other than obfuscating the code. Open code and kill it. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 6ee76a8..48a3ed4 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -332,21 +332,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) return NULL; } -/** - * sysfs_attach_dentry - associate sysfs_dirent with dentry - * @sd: target sysfs_dirent - * @dentry: dentry to associate - * - * LOCKING: - * mutex_lock(sysfs_mutex) - */ -static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry) -{ - dentry->d_op = &sysfs_dentry_ops; - dentry->d_fsdata = sysfs_get(sd); - d_rehash(dentry); -} - static int sysfs_ilookup_test(struct inode *inode, void *arg) { struct sysfs_dirent *sd = arg; @@ -696,8 +681,11 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, goto out_unlock; } + /* instantiate and hash dentry */ + dentry->d_op = &sysfs_dentry_ops; + dentry->d_fsdata = sysfs_get(sd); d_instantiate(dentry, inode); - sysfs_attach_dentry(sd, dentry); + d_rehash(dentry); out_unlock: mutex_unlock(&sysfs_mutex); -- cgit v0.10.2 From dc2f75f0e0cac645c22c85bcf429683b3fa0d2d9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:12 +0900 Subject: sysfs: make sysfs_root a regular directory dirent sysfs_root is different from a regular directory dirent in that it's of type SYSFS_ROOT and doesn't have a name. These differences aren't used by anybody and only adds to complexity. Make sysfs_root a regular directory dirent. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index b6ac4e6..c40fb9f 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -157,11 +157,6 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) /* initialize inode according to type */ switch (sysfs_type(sd)) { - case SYSFS_ROOT: - inode->i_op = &sysfs_dir_inode_operations; - inode->i_fop = &sysfs_dir_operations; - inc_nlink(inode); /* directory, account for "." */ - break; case SYSFS_DIR: inode->i_op = &sysfs_dir_inode_operations; inode->i_fop = &sysfs_dir_operations; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 28bf359..465902c 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -24,8 +24,9 @@ static const struct super_operations sysfs_ops = { }; struct sysfs_dirent sysfs_root = { + .s_name = "", .s_count = ATOMIC_INIT(1), - .s_flags = SYSFS_ROOT, + .s_flags = SYSFS_DIR, .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, .s_ino = 1, }; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 2a68bfa..60405a6 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -48,11 +48,10 @@ struct sysfs_dirent { #define SD_DEACTIVATED_BIAS INT_MIN #define SYSFS_TYPE_MASK 0x00ff -#define SYSFS_ROOT 0x0001 -#define SYSFS_DIR 0x0002 -#define SYSFS_KOBJ_ATTR 0x0004 -#define SYSFS_KOBJ_BIN_ATTR 0x0008 -#define SYSFS_KOBJ_LINK 0x0020 +#define SYSFS_DIR 0x0001 +#define SYSFS_KOBJ_ATTR 0x0002 +#define SYSFS_KOBJ_BIN_ATTR 0x0004 +#define SYSFS_KOBJ_LINK 0x0008 #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) #define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK -- cgit v0.10.2 From bc747f37a0f089b9366f7385ff870e12911f2383 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:12 +0900 Subject: sysfs: move sysfs_dirent->s_children into sysfs_dirent->s_dir Children list head is only meaninful for directory nodes. Move it into s_dir. This doesn't save any space currently but it will with further changes. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 48a3ed4..4ad9422 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -26,7 +26,7 @@ static DEFINE_IDA(sysfs_ino_ida); * @sd: sysfs_dirent of interest * * Link @sd into its sibling list which starts from - * sd->s_parent->s_children. + * sd->s_parent->s_dir.children. * * Locking: * mutex_lock(sysfs_mutex) @@ -40,9 +40,9 @@ static void sysfs_link_sibling(struct sysfs_dirent *sd) /* Store directory entries in order by ino. This allows * readdir to properly restart without having to add a - * cursor into the s_children list. + * cursor into the s_dir.children list. */ - for (pos = &parent_sd->s_children; *pos; pos = &(*pos)->s_sibling) { + for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) { if (sd->s_ino < (*pos)->s_ino) break; } @@ -55,7 +55,7 @@ static void sysfs_link_sibling(struct sysfs_dirent *sd) * @sd: sysfs_dirent of interest * * Unlink @sd from its sibling list which starts from - * sd->s_parent->s_children. + * sd->s_parent->s_dir.children. * * Locking: * mutex_lock(sysfs_mutex) @@ -64,7 +64,8 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) { struct sysfs_dirent **pos; - for (pos = &sd->s_parent->s_children; *pos; pos = &(*pos)->s_sibling) { + for (pos = &sd->s_parent->s_dir.children; *pos; + pos = &(*pos)->s_sibling) { if (*pos == sd) { *pos = sd->s_sibling; sd->s_sibling = NULL; @@ -570,7 +571,7 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, { struct sysfs_dirent *sd; - for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) + for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) if (!strcmp(sd->s_name, name)) return sd; return NULL; @@ -722,7 +723,7 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); sysfs_addrm_start(&acxt, dir_sd); - pos = &dir_sd->s_children; + pos = &dir_sd->s_dir.children; while (*pos) { struct sysfs_dirent *sd = *pos; @@ -922,7 +923,7 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) mutex_lock(&sysfs_mutex); /* Skip the dentries we have already reported */ - pos = parent_sd->s_children; + pos = parent_sd->s_dir.children; while (pos && (filp->f_pos > pos->s_ino)) pos = pos->s_sibling; diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index c40fb9f..2210cf0 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -127,7 +127,7 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd) struct sysfs_dirent *child; int nr = 0; - for (child = sd->s_children; child; child = child->s_sibling) + for (child = sd->s_dir.children; child; child = child->s_sibling) if (sysfs_type(child) == SYSFS_DIR) nr++; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 60405a6..42b0327 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -1,6 +1,8 @@ /* type-specific structures for sysfs_dirent->s_* union members */ struct sysfs_elem_dir { struct kobject *kobj; + /* children list starts here and goes through sd->s_sibling */ + struct sysfs_dirent *children; }; struct sysfs_elem_symlink { @@ -28,7 +30,6 @@ struct sysfs_dirent { atomic_t s_active; struct sysfs_dirent *s_parent; struct sysfs_dirent *s_sibling; - struct sysfs_dirent *s_children; const char *s_name; union { -- cgit v0.10.2 From 85a4ffad3de77177591f7c2c18c26c3c8dd28bff Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:12 +0900 Subject: sysfs: implement sysfs_open_dirent Implement sysfs_open_dirent which represents an open file (attribute) sysfs_dirent. A file sysfs_dirent with one or more open files have one sysfs_dirent and all sysfs_buffers (one for each open instance) are linked to it. sysfs_open_dirent doesn't actually do anything yet but will be used to off-load things which are specific for open file sysfs_dirent from it. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 3c91a57..b13ba94 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -49,6 +49,22 @@ static struct sysfs_ops subsys_sysfs_ops = { .store = subsys_attr_store, }; +/* + * There's one sysfs_buffer for each open file and one + * sysfs_open_dirent for each sysfs_dirent with one or more open + * files. + * + * filp->private_data points to sysfs_buffer and + * sysfs_dirent->s_attr.open points to sysfs_open_dirent. s_attr.open + * is protected by sysfs_open_dirent_lock. + */ +static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED; + +struct sysfs_open_dirent { + atomic_t refcnt; + struct list_head buffers; /* goes through sysfs_buffer.list */ +}; + struct sysfs_buffer { size_t count; loff_t pos; @@ -57,6 +73,7 @@ struct sysfs_buffer { struct mutex mutex; int needs_read_fill; int event; + struct list_head list; }; /** @@ -237,6 +254,86 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t return len; } +/** + * sysfs_get_open_dirent - get or create sysfs_open_dirent + * @sd: target sysfs_dirent + * @buffer: sysfs_buffer for this instance of open + * + * If @sd->s_attr.open exists, increment its reference count; + * otherwise, create one. @buffer is chained to the buffers + * list. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sysfs_get_open_dirent(struct sysfs_dirent *sd, + struct sysfs_buffer *buffer) +{ + struct sysfs_open_dirent *od, *new_od = NULL; + + retry: + spin_lock(&sysfs_open_dirent_lock); + + if (!sd->s_attr.open && new_od) { + sd->s_attr.open = new_od; + new_od = NULL; + } + + od = sd->s_attr.open; + if (od) { + atomic_inc(&od->refcnt); + list_add_tail(&buffer->list, &od->buffers); + } + + spin_unlock(&sysfs_open_dirent_lock); + + if (od) { + kfree(new_od); + return 0; + } + + /* not there, initialize a new one and retry */ + new_od = kmalloc(sizeof(*new_od), GFP_KERNEL); + if (!new_od) + return -ENOMEM; + + atomic_set(&new_od->refcnt, 0); + INIT_LIST_HEAD(&new_od->buffers); + goto retry; +} + +/** + * sysfs_put_open_dirent - put sysfs_open_dirent + * @sd: target sysfs_dirent + * @buffer: associated sysfs_buffer + * + * Put @sd->s_attr.open and unlink @buffer from the buffers list. + * If reference count reaches zero, disassociate and free it. + * + * LOCKING: + * None. + */ +static void sysfs_put_open_dirent(struct sysfs_dirent *sd, + struct sysfs_buffer *buffer) +{ + struct sysfs_open_dirent *od = sd->s_attr.open; + + spin_lock(&sysfs_open_dirent_lock); + + list_del(&buffer->list); + if (atomic_dec_and_test(&od->refcnt)) + sd->s_attr.open = NULL; + else + od = NULL; + + spin_unlock(&sysfs_open_dirent_lock); + + kfree(od); +} + static int sysfs_open_file(struct inode *inode, struct file *file) { struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; @@ -298,19 +395,29 @@ static int sysfs_open_file(struct inode *inode, struct file *file) buffer->ops = ops; file->private_data = buffer; + /* make sure we have open dirent struct */ + error = sysfs_get_open_dirent(attr_sd, buffer); + if (error) + goto err_free; + /* open succeeded, put active references */ sysfs_put_active_two(attr_sd); return 0; + err_free: + kfree(buffer); err_out: sysfs_put_active_two(attr_sd); return error; } -static int sysfs_release(struct inode * inode, struct file * filp) +static int sysfs_release(struct inode *inode, struct file *filp) { + struct sysfs_dirent *sd = filp->f_path.dentry->d_fsdata; struct sysfs_buffer *buffer = filp->private_data; + sysfs_put_open_dirent(sd, buffer); + if (buffer->page) free_page((unsigned long)buffer->page); kfree(buffer); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 42b0327..3adce7d 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -1,3 +1,5 @@ +struct sysfs_open_dirent; + /* type-specific structures for sysfs_dirent->s_* union members */ struct sysfs_elem_dir { struct kobject *kobj; @@ -11,6 +13,7 @@ struct sysfs_elem_symlink { struct sysfs_elem_attr { struct attribute *attr; + struct sysfs_open_dirent *open; }; struct sysfs_elem_bin_attr { -- cgit v0.10.2 From a4e8b912541d5372ae049a3b7c1979968e52c40b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:12 +0900 Subject: sysfs: move sysfs file poll implementation to sysfs_open_dirent Sysfs file poll implementation is scattered over sysfs and kobject. Event numbering is done in sysfs_dirent but wait itself is done on kobject. This not only unecessarily bloats both kobject and sysfs_dirent but is also buggy - if a sysfs_dirent is removed while there still are pollers, the associaton betwen the kobject and sysfs_dirent breaks and kobject may be freed with the pollers still sleeping on it. This patch moves whole poll implementation into sysfs_open_dirent. Each time a sysfs_open_dirent is created, event number restarts from 1 and pollers sleep on sysfs_open_dirent. As event sequence number is meaningless without any open file and pollers should have open file and thus sysfs_open_dirent, this ephemeral event counting works and is a saner implementation. This patch fixes the dnagling sleepers bug and reduces the sizes of kobject and sysfs_dirent by one pointer. Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 4ad9422..e301a12 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -318,7 +318,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) atomic_set(&sd->s_count, 1); atomic_set(&sd->s_active, 0); - atomic_set(&sd->s_event, 1); sd->s_name = name; sd->s_mode = mode; diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index b13ba94..c05f961 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -62,6 +62,8 @@ static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED; struct sysfs_open_dirent { atomic_t refcnt; + atomic_t event; + wait_queue_head_t poll; struct list_head buffers; /* goes through sysfs_buffer.list */ }; @@ -104,7 +106,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer if (!sysfs_get_active_two(attr_sd)) return -ENODEV; - buffer->event = atomic_read(&attr_sd->s_event); + buffer->event = atomic_read(&attr_sd->s_attr.open->event); count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page); sysfs_put_active_two(attr_sd); @@ -301,6 +303,8 @@ static int sysfs_get_open_dirent(struct sysfs_dirent *sd, return -ENOMEM; atomic_set(&new_od->refcnt, 0); + atomic_set(&new_od->event, 1); + init_waitqueue_head(&new_od->poll); INIT_LIST_HEAD(&new_od->buffers); goto retry; } @@ -443,17 +447,17 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait) { struct sysfs_buffer * buffer = filp->private_data; struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; - struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; + struct sysfs_open_dirent *od = attr_sd->s_attr.open; /* need parent for the kobj, grab both */ if (!sysfs_get_active_two(attr_sd)) goto trigger; - poll_wait(filp, &kobj->poll, wait); + poll_wait(filp, &od->poll, wait); sysfs_put_active_two(attr_sd); - if (buffer->event != atomic_read(&attr_sd->s_event)) + if (buffer->event != atomic_read(&od->event)) goto trigger; return 0; @@ -474,8 +478,17 @@ void sysfs_notify(struct kobject *k, char *dir, char *attr) if (sd && attr) sd = sysfs_find_dirent(sd, attr); if (sd) { - atomic_inc(&sd->s_event); - wake_up_interruptible(&k->poll); + struct sysfs_open_dirent *od; + + spin_lock(&sysfs_open_dirent_lock); + + od = sd->s_attr.open; + if (od) { + atomic_inc(&od->event); + wake_up_interruptible(&od->poll); + } + + spin_unlock(&sysfs_open_dirent_lock); } mutex_unlock(&sysfs_mutex); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 3adce7d..269c845 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -46,7 +46,6 @@ struct sysfs_dirent { ino_t s_ino; umode_t s_mode; struct iattr *s_iattr; - atomic_t s_event; }; #define SD_DEACTIVATED_BIAS INT_MIN diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 0777b3f..a8a84fc 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -66,7 +66,6 @@ struct kobject { struct kset * kset; struct kobj_type * ktype; struct sysfs_dirent * sd; - wait_queue_head_t poll; }; extern int kobject_set_name(struct kobject *, const char *, ...) diff --git a/lib/kobject.c b/lib/kobject.c index e8181d3..fc6db6b 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -131,7 +131,6 @@ void kobject_init(struct kobject * kobj) return; kref_init(&kobj->kref); INIT_LIST_HEAD(&kobj->entry); - init_waitqueue_head(&kobj->poll); kobj->kset = kset_get(kobj->kset); } -- cgit v0.10.2 From e4bc16621d82ee1fd3685dcbf889a7c49891847b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 26 Sep 2007 11:12:00 -0700 Subject: driver core: remove subsystem_init() There is only one user of it, and it is only a wrapper for kset_init(). Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt index 5e7aca2..ca86a88 100644 --- a/Documentation/kobject.txt +++ b/Documentation/kobject.txt @@ -238,7 +238,6 @@ kobj_set_kset_s(obj,subsys) - Assumes that obj->kobj exists, and is a struct kobject. - Sets the kset of that kobject to the kset . -void subsystem_init(struct kset *s); int subsystem_register(struct kset *s); void subsystem_unregister(struct kset *s); diff --git a/drivers/base/class.c b/drivers/base/class.c index 3e9b04c..5b9cf06 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -861,7 +861,7 @@ int __init classes_init(void) /* ick, this is ugly, the things we go through to keep from showing up * in sysfs... */ - subsystem_init(&class_obj_subsys); + kset_init(&class_obj_subsys); if (!class_obj_subsys.kobj.parent) class_obj_subsys.kobj.parent = &class_obj_subsys.kobj; return 0; diff --git a/include/linux/kobject.h b/include/linux/kobject.h index a8a84fc..05cc5b2 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -217,7 +217,6 @@ extern struct kset hypervisor_subsys; #define kobj_set_kset_s(obj,subsys) \ (obj)->kobj.kset = &(subsys) -extern void subsystem_init(struct kset *); extern int __must_check subsystem_register(struct kset *); extern void subsystem_unregister(struct kset *); diff --git a/lib/kobject.c b/lib/kobject.c index fc6db6b..b7e0646 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -617,11 +617,6 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name) return ret; } -void subsystem_init(struct kset *s) -{ - kset_init(s); -} - int subsystem_register(struct kset *s) { return kset_register(s); -- cgit v0.10.2 From adc56808f32e15fa0c0fcd5ecb4b30989076ef2b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 11 Oct 2007 10:47:49 -0600 Subject: Driver core: rename ktype_class This makes it a bit more sane when trying to figure out how to clean up the ktype mess. Based on a larger patch from Kay Sievers Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/class.c b/drivers/base/class.c index 5b9cf06..a863bb0 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -65,13 +65,13 @@ static struct sysfs_ops class_sysfs_ops = { .store = class_attr_store, }; -static struct kobj_type ktype_class = { +static struct kobj_type class_ktype = { .sysfs_ops = &class_sysfs_ops, .release = class_release, }; /* Hotplug events for classes go to the class_obj subsys */ -static decl_subsys(class, &ktype_class, NULL); +static decl_subsys(class, &class_ktype, NULL); int class_create_file(struct class * cls, const struct class_attribute * attr) @@ -323,7 +323,7 @@ static void class_dev_release(struct kobject * kobj) } } -static struct kobj_type ktype_class_device = { +static struct kobj_type class_device_ktype = { .sysfs_ops = &class_dev_sysfs_ops, .release = class_dev_release, }; @@ -332,7 +332,7 @@ static int class_uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); - if (ktype == &ktype_class_device) { + if (ktype == &class_device_ktype) { struct class_device *class_dev = to_class_dev(kobj); if (class_dev->class) return 1; @@ -452,7 +452,7 @@ static struct kset_uevent_ops class_uevent_ops = { .uevent = class_uevent, }; -static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops); +static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops); static int class_device_add_attrs(struct class_device * cd) -- cgit v0.10.2 From 8f4afc410b8d2be49f34835b6bbe788f50471b02 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 11 Oct 2007 10:47:49 -0600 Subject: Driver core: rename ktype_device This makes it a bit more sane when trying to figure out how to clean up the ktype mess. Based on a larger patch from Kay Sievers Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/core.c b/drivers/base/core.c index 65de221..c134341 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -108,7 +108,7 @@ static void device_release(struct kobject * kobj) } } -static struct kobj_type ktype_device = { +static struct kobj_type device_ktype = { .release = device_release, .sysfs_ops = &dev_sysfs_ops, }; @@ -118,7 +118,7 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); - if (ktype == &ktype_device) { + if (ktype == &device_ktype) { struct device *dev = to_dev(kobj); if (dev->uevent_suppress) return 0; @@ -405,7 +405,7 @@ static struct device_attribute devt_attr = * devices_subsys - structure to be registered with kobject core. */ -decl_subsys(devices, &ktype_device, &device_uevent_ops); +decl_subsys(devices, &device_ktype, &device_uevent_ops); /** -- cgit v0.10.2 From a1148fb03f3c5d0bb5e6641234c2251a15741361 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 11 Oct 2007 10:47:49 -0600 Subject: Driver core: rename ktype_driver This makes it a bit more sane when trying to figure out how to clean up the ktype mess. Based on a larger patch from Kay Sievers Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 6768a01..9a19b07 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -89,7 +89,7 @@ static void driver_release(struct kobject * kobj) */ } -static struct kobj_type ktype_driver = { +static struct kobj_type driver_ktype = { .sysfs_ops = &driver_sysfs_ops, .release = driver_release, }; @@ -868,7 +868,7 @@ int bus_register(struct bus_type * bus) kobject_set_name(&bus->drivers.kobj, "drivers"); bus->drivers.kobj.parent = &bus->subsys.kobj; - bus->drivers.ktype = &ktype_driver; + bus->drivers.ktype = &driver_ktype; retval = kset_register(&bus->drivers); if (retval) goto bus_drivers_fail; -- cgit v0.10.2 From e89a4116ef345cf10c21f722dd1d8bfa9b7c7d58 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 11 Oct 2007 10:47:49 -0600 Subject: Driver core: rename ktype_edd and ktype_efivar This makes it a bit more sane when trying to figure out how to clean up the ktype mess. Based on a larger patch from Kay Sievers Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 0fb730e..6942e06 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -625,13 +625,13 @@ static void edd_release(struct kobject * kobj) kfree(dev); } -static struct kobj_type ktype_edd = { +static struct kobj_type edd_ktype = { .release = edd_release, .sysfs_ops = &edd_attr_ops, .default_attrs = def_attrs, }; -static decl_subsys(edd,&ktype_edd,NULL); +static decl_subsys(edd, &edd_ktype, NULL); /** diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index bfd2d67..858a7b9 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -402,7 +402,7 @@ static struct attribute *def_attrs[] = { NULL, }; -static struct kobj_type ktype_efivar = { +static struct kobj_type efivar_ktype = { .release = efivar_release, .sysfs_ops = &efivar_attr_ops, .default_attrs = def_attrs, @@ -583,7 +583,7 @@ static struct subsys_attribute *efi_subsys_attrs[] = { NULL, /* maybe more in the future? */ }; -static decl_subsys(vars, &ktype_efivar, NULL); +static decl_subsys(vars, &efivar_ktype, NULL); static decl_subsys(efi, NULL, NULL); /* -- cgit v0.10.2 From 6adf7554b9c70eac83251e00aa4a55f7dc830cec Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Sep 2007 14:48:53 -0700 Subject: kset: add some kerneldoc to help describe what these strange things are Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 05cc5b2..973aa7b 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -117,29 +117,30 @@ struct kset_uevent_ops { struct kobj_uevent_env *env); }; -/* - * struct kset - a set of kobjects of a specific type, belonging - * to a specific subsystem. - * - * All kobjects of a kset should be embedded in an identical - * type. This type may have a descriptor, which the kset points - * to. This allows there to exist sets of objects of the same - * type in different subsystems. +/** + * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem. * - * A subsystem does not have to be a list of only one type - * of object; multiple ksets can belong to one subsystem. All - * ksets of a subsystem share the subsystem's lock. + * A kset defines a group of kobjects. They can be individually + * different "types" but overall these kobjects all want to be grouped + * together and operated on in the same manner. ksets are used to + * define the attribute callbacks and other common events that happen to + * a kobject. * - * Each kset can support specific event variables; it can - * supress the event generation or add subsystem specific - * variables carried with the event. + * @ktype: the struct kobj_type for this specific kset + * @list: the list of all kobjects for this kset + * @list_lock: a lock for iterating over the kobjects + * @kobj: the embedded kobject for this kset (recursion, isn't it fun...) + * @uevent_ops: the set of uevent operations for this kset. These are + * called whenever a kobject has something happen to it so that the kset + * can add new environment variables, or filter out the uevents if so + * desired. */ struct kset { - struct kobj_type * ktype; + struct kobj_type *ktype; struct list_head list; spinlock_t list_lock; struct kobject kobj; - struct kset_uevent_ops * uevent_ops; + struct kset_uevent_ops *uevent_ops; }; -- cgit v0.10.2 From f0e7e1bd77d450ebfa12153b90f93ad46616ab4a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Sep 2007 14:48:53 -0700 Subject: kobject: update the copyrights I've been hacking on these files for a while now, might as well make it official... Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 973aa7b..4a0d27f 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -1,8 +1,10 @@ /* * kobject.h - generic kernel object infrastructure. * - * Copyright (c) 2002-2003 Patrick Mochel - * Copyright (c) 2002-2003 Open Source Development Labs + * Copyright (c) 2002-2003 Patrick Mochel + * Copyright (c) 2002-2003 Open Source Development Labs + * Copyright (c) 2006-2007 Greg Kroah-Hartman + * Copyright (c) 2006-2007 Novell Inc. * * This file is released under the GPLv2. * diff --git a/lib/kobject.c b/lib/kobject.c index b7e0646..03d4036 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -2,6 +2,8 @@ * kobject.c - library routines for handling generic kernel objects * * Copyright (c) 2002-2003 Patrick Mochel + * Copyright (c) 2006-2007 Greg Kroah-Hartman + * Copyright (c) 2006-2007 Novell Inc. * * This file is released under the GPLv2. * -- cgit v0.10.2 From 6d66f5cd26e4c482e986130b7572f2735a0f7e8b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 17:31:38 +0900 Subject: sysfs: add copyrights Sysfs has gone through considerable amount of reimplementation. Add copyrights. Any objections? :-) Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 247ea19..006fc64 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -1,9 +1,15 @@ /* - * bin.c - binary file operations for sysfs. + * fs/sysfs/bin.c - sysfs binary file implementation * * Copyright (c) 2003 Patrick Mochel * Copyright (c) 2003 Matthew Wilcox * Copyright (c) 2004 Silicon Graphics, Inc. + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. + * + * Please see Documentation/filesystems/sysfs.txt for more information. */ #undef DEBUG diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index e301a12..9161db4 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -1,5 +1,13 @@ /* - * dir.c - Operations for sysfs directories. + * fs/sysfs/dir.c - sysfs core and dir operation implementation + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. + * + * Please see Documentation/filesystems/sysfs.txt for more information. */ #undef DEBUG diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index c05f961..d3be1e7 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -1,5 +1,13 @@ /* - * file.c - operations for regular (text) files. + * fs/sysfs/file.c - sysfs regular (text) file implementation + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. + * + * Please see Documentation/filesystems/sysfs.txt for more information. */ #include diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 2210cf0..9236635 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -1,7 +1,11 @@ /* - * inode.c - basic inode and dentry operations. + * fs/sysfs/inode.c - basic sysfs inode and dentry operations * - * sysfs is Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. * * Please see Documentation/filesystems/sysfs.txt for more information. */ diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 465902c..c76c540 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -1,5 +1,13 @@ /* - * mount.c - operations for initializing and mounting sysfs. + * fs/sysfs/symlink.c - operations for initializing and mounting sysfs + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. + * + * Please see Documentation/filesystems/sysfs.txt for more information. */ #define DEBUG diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index ffa82e9..3eac20c 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -1,5 +1,13 @@ /* - * symlink.c - operations for sysfs symlinks. + * fs/sysfs/symlink.c - sysfs symlink implementation + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. + * + * Please see Documentation/filesystems/sysfs.txt for more information. */ #include diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 269c845..f0326f2 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -1,3 +1,13 @@ +/* + * fs/sysfs/sysfs.h - sysfs internal header file + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. + */ + struct sysfs_open_dirent; /* type-specific structures for sysfs_dirent->s_* union members */ diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index db5dd24..149ab62 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -3,6 +3,8 @@ * * Copyright (c) 2001,2002 Patrick Mochel * Copyright (c) 2004 Silicon Graphics, Inc. + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo * * Please see Documentation/filesystems/sysfs.txt for more information. */ -- cgit v0.10.2 From cd59abfcc441b2abb4cf2cd62c1eb0f02a60e8dd Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 21 Sep 2007 15:36:56 -0400 Subject: PM: merge device power-management source files This patch (as993) merges the suspend.c and resume.c files in drivers/base/power into main.c, making some public symbols private. Signed-off-by: Alan Stern Acked-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 9caeaea..a803733 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -1,5 +1,5 @@ obj-y := shutdown.o -obj-$(CONFIG_PM_SLEEP) += main.o suspend.o resume.o sysfs.o +obj-$(CONFIG_PM_SLEEP) += main.o sysfs.o obj-$(CONFIG_PM_TRACE) += trace.o ifeq ($(CONFIG_DEBUG_DRIVER),y) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index eb9f38d..0ab4ab2 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -20,19 +20,24 @@ */ #include +#include #include +#include +#include +#include "../base.h" #include "power.h" LIST_HEAD(dpm_active); -LIST_HEAD(dpm_off); -LIST_HEAD(dpm_off_irq); +static LIST_HEAD(dpm_off); +static LIST_HEAD(dpm_off_irq); -DEFINE_MUTEX(dpm_mtx); -DEFINE_MUTEX(dpm_list_mtx); +static DEFINE_MUTEX(dpm_mtx); +static DEFINE_MUTEX(dpm_list_mtx); int (*platform_enable_wakeup)(struct device *dev, int is_on); + int device_pm_add(struct device *dev) { int error; @@ -61,3 +66,334 @@ void device_pm_remove(struct device *dev) } +/*------------------------- Resume routines -------------------------*/ + +/** + * resume_device - Restore state for one device. + * @dev: Device. + * + */ + +static int resume_device(struct device * dev) +{ + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + + down(&dev->sem); + + if (dev->bus && dev->bus->resume) { + dev_dbg(dev,"resuming\n"); + error = dev->bus->resume(dev); + } + + if (!error && dev->type && dev->type->resume) { + dev_dbg(dev,"resuming\n"); + error = dev->type->resume(dev); + } + + if (!error && dev->class && dev->class->resume) { + dev_dbg(dev,"class resume\n"); + error = dev->class->resume(dev); + } + + up(&dev->sem); + + TRACE_RESUME(error); + return error; +} + + +static int resume_device_early(struct device * dev) +{ + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + if (dev->bus && dev->bus->resume_early) { + dev_dbg(dev,"EARLY resume\n"); + error = dev->bus->resume_early(dev); + } + TRACE_RESUME(error); + return error; +} + +/* + * Resume the devices that have either not gone through + * the late suspend, or that did go through it but also + * went through the early resume + */ +static void dpm_resume(void) +{ + mutex_lock(&dpm_list_mtx); + while(!list_empty(&dpm_off)) { + struct list_head * entry = dpm_off.next; + struct device * dev = to_device(entry); + + get_device(dev); + list_move_tail(entry, &dpm_active); + + mutex_unlock(&dpm_list_mtx); + resume_device(dev); + mutex_lock(&dpm_list_mtx); + put_device(dev); + } + mutex_unlock(&dpm_list_mtx); +} + + +/** + * device_resume - Restore state of each device in system. + * + * Walk the dpm_off list, remove each entry, resume the device, + * then add it to the dpm_active list. + */ + +void device_resume(void) +{ + might_sleep(); + mutex_lock(&dpm_mtx); + dpm_resume(); + mutex_unlock(&dpm_mtx); +} + +EXPORT_SYMBOL_GPL(device_resume); + + +/** + * dpm_power_up - Power on some devices. + * + * Walk the dpm_off_irq list and power each device up. This + * is used for devices that required they be powered down with + * interrupts disabled. As devices are powered on, they are moved + * to the dpm_active list. + * + * Interrupts must be disabled when calling this. + */ + +static void dpm_power_up(void) +{ + while(!list_empty(&dpm_off_irq)) { + struct list_head * entry = dpm_off_irq.next; + struct device * dev = to_device(entry); + + list_move_tail(entry, &dpm_off); + resume_device_early(dev); + } +} + + +/** + * device_power_up - Turn on all devices that need special attention. + * + * Power on system devices then devices that required we shut them down + * with interrupts disabled. + * Called with interrupts disabled. + */ + +void device_power_up(void) +{ + sysdev_resume(); + dpm_power_up(); +} + +EXPORT_SYMBOL_GPL(device_power_up); + + +/*------------------------- Suspend routines -------------------------*/ + +/* + * The entries in the dpm_active list are in a depth first order, simply + * because children are guaranteed to be discovered after parents, and + * are inserted at the back of the list on discovery. + * + * All list on the suspend path are done in reverse order, so we operate + * on the leaves of the device tree (or forests, depending on how you want + * to look at it ;) first. As nodes are removed from the back of the list, + * they are inserted into the front of their destintation lists. + * + * Things are the reverse on the resume path - iterations are done in + * forward order, and nodes are inserted at the back of their destination + * lists. This way, the ancestors will be accessed before their descendents. + */ + +static inline char *suspend_verb(u32 event) +{ + switch (event) { + case PM_EVENT_SUSPEND: return "suspend"; + case PM_EVENT_FREEZE: return "freeze"; + case PM_EVENT_PRETHAW: return "prethaw"; + default: return "(unknown suspend event)"; + } +} + + +static void +suspend_device_dbg(struct device *dev, pm_message_t state, char *info) +{ + dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event), + ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ? + ", may wakeup" : ""); +} + +/** + * suspend_device - Save state of one device. + * @dev: Device. + * @state: Power state device is entering. + */ + +static int suspend_device(struct device * dev, pm_message_t state) +{ + int error = 0; + + down(&dev->sem); + if (dev->power.power_state.event) { + dev_dbg(dev, "PM: suspend %d-->%d\n", + dev->power.power_state.event, state.event); + } + + if (dev->class && dev->class->suspend) { + suspend_device_dbg(dev, state, "class "); + error = dev->class->suspend(dev, state); + suspend_report_result(dev->class->suspend, error); + } + + if (!error && dev->type && dev->type->suspend) { + suspend_device_dbg(dev, state, "type "); + error = dev->type->suspend(dev, state); + suspend_report_result(dev->type->suspend, error); + } + + if (!error && dev->bus && dev->bus->suspend) { + suspend_device_dbg(dev, state, ""); + error = dev->bus->suspend(dev, state); + suspend_report_result(dev->bus->suspend, error); + } + up(&dev->sem); + return error; +} + + +/* + * This is called with interrupts off, only a single CPU + * running. We can't acquire a mutex or semaphore (and we don't + * need the protection) + */ +static int suspend_device_late(struct device *dev, pm_message_t state) +{ + int error = 0; + + if (dev->bus && dev->bus->suspend_late) { + suspend_device_dbg(dev, state, "LATE "); + error = dev->bus->suspend_late(dev, state); + suspend_report_result(dev->bus->suspend_late, error); + } + return error; +} + +/** + * device_suspend - Save state and stop all devices in system. + * @state: Power state to put each device in. + * + * Walk the dpm_active list, call ->suspend() for each device, and move + * it to the dpm_off list. + * + * (For historical reasons, if it returns -EAGAIN, that used to mean + * that the device would be called again with interrupts disabled. + * These days, we use the "suspend_late()" callback for that, so we + * print a warning and consider it an error). + * + * If we get a different error, try and back out. + * + * If we hit a failure with any of the devices, call device_resume() + * above to bring the suspended devices back to life. + * + */ + +int device_suspend(pm_message_t state) +{ + int error = 0; + + might_sleep(); + mutex_lock(&dpm_mtx); + mutex_lock(&dpm_list_mtx); + while (!list_empty(&dpm_active) && error == 0) { + struct list_head * entry = dpm_active.prev; + struct device * dev = to_device(entry); + + get_device(dev); + mutex_unlock(&dpm_list_mtx); + + error = suspend_device(dev, state); + + mutex_lock(&dpm_list_mtx); + + /* Check if the device got removed */ + if (!list_empty(&dev->power.entry)) { + /* Move it to the dpm_off list */ + if (!error) + list_move(&dev->power.entry, &dpm_off); + } + if (error) + printk(KERN_ERR "Could not suspend device %s: " + "error %d%s\n", + kobject_name(&dev->kobj), error, + error == -EAGAIN ? " (please convert to suspend_late)" : ""); + put_device(dev); + } + mutex_unlock(&dpm_list_mtx); + if (error) + dpm_resume(); + + mutex_unlock(&dpm_mtx); + return error; +} + +EXPORT_SYMBOL_GPL(device_suspend); + +/** + * device_power_down - Shut down special devices. + * @state: Power state to enter. + * + * Walk the dpm_off_irq list, calling ->power_down() for each device that + * couldn't power down the device with interrupts enabled. When we're + * done, power down system devices. + */ + +int device_power_down(pm_message_t state) +{ + int error = 0; + struct device * dev; + + while (!list_empty(&dpm_off)) { + struct list_head * entry = dpm_off.prev; + + dev = to_device(entry); + error = suspend_device_late(dev, state); + if (error) + goto Error; + list_move(&dev->power.entry, &dpm_off_irq); + } + + error = sysdev_suspend(state); + Done: + return error; + Error: + printk(KERN_ERR "Could not power down device %s: " + "error %d\n", kobject_name(&dev->kobj), error); + dpm_power_up(); + goto Done; +} + +EXPORT_SYMBOL_GPL(device_power_down); + +void __suspend_report_result(const char *function, void *fn, int ret) +{ + if (ret) { + printk(KERN_ERR "%s(): ", function); + print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); + printk("%d\n", ret); + } +} +EXPORT_SYMBOL_GPL(__suspend_report_result); diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 49e64db..5c4efd4 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -11,32 +11,11 @@ extern void device_shutdown(void); * main.c */ -/* - * Used to synchronize global power management operations. - */ -extern struct mutex dpm_mtx; - -/* - * Used to serialize changes to the dpm_* lists. - */ -extern struct mutex dpm_list_mtx; - -/* - * The PM lists. - */ -extern struct list_head dpm_active; -extern struct list_head dpm_off; -extern struct list_head dpm_off_irq; - - -static inline struct dev_pm_info * to_pm_info(struct list_head * entry) -{ - return container_of(entry, struct dev_pm_info, entry); -} +extern struct list_head dpm_active; /* The active device list */ static inline struct device * to_device(struct list_head * entry) { - return container_of(to_pm_info(entry), struct device, power); + return container_of(entry, struct device, power.entry); } extern int device_pm_add(struct device *); @@ -49,13 +28,6 @@ extern void device_pm_remove(struct device *); extern int dpm_sysfs_add(struct device *); extern void dpm_sysfs_remove(struct device *); -/* - * resume.c - */ - -extern void dpm_resume(void); -extern void dpm_power_up(void); - #else /* CONFIG_PM_SLEEP */ diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c deleted file mode 100644 index 67948ba..0000000 --- a/drivers/base/power/resume.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * resume.c - Functions for waking devices up. - * - * Copyright (c) 2003 Patrick Mochel - * Copyright (c) 2003 Open Source Development Labs - * - * This file is released under the GPLv2 - * - */ - -#include -#include -#include "../base.h" -#include "power.h" - - -/** - * resume_device - Restore state for one device. - * @dev: Device. - * - */ - -static int resume_device(struct device * dev) -{ - int error = 0; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); - - down(&dev->sem); - - if (dev->bus && dev->bus->resume) { - dev_dbg(dev,"resuming\n"); - error = dev->bus->resume(dev); - } - - if (!error && dev->type && dev->type->resume) { - dev_dbg(dev,"resuming\n"); - error = dev->type->resume(dev); - } - - if (!error && dev->class && dev->class->resume) { - dev_dbg(dev,"class resume\n"); - error = dev->class->resume(dev); - } - - up(&dev->sem); - - TRACE_RESUME(error); - return error; -} - - -static int resume_device_early(struct device * dev) -{ - int error = 0; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); - if (dev->bus && dev->bus->resume_early) { - dev_dbg(dev,"EARLY resume\n"); - error = dev->bus->resume_early(dev); - } - TRACE_RESUME(error); - return error; -} - -/* - * Resume the devices that have either not gone through - * the late suspend, or that did go through it but also - * went through the early resume - */ -void dpm_resume(void) -{ - mutex_lock(&dpm_list_mtx); - while(!list_empty(&dpm_off)) { - struct list_head * entry = dpm_off.next; - struct device * dev = to_device(entry); - - get_device(dev); - list_move_tail(entry, &dpm_active); - - mutex_unlock(&dpm_list_mtx); - resume_device(dev); - mutex_lock(&dpm_list_mtx); - put_device(dev); - } - mutex_unlock(&dpm_list_mtx); -} - - -/** - * device_resume - Restore state of each device in system. - * - * Walk the dpm_off list, remove each entry, resume the device, - * then add it to the dpm_active list. - */ - -void device_resume(void) -{ - might_sleep(); - mutex_lock(&dpm_mtx); - dpm_resume(); - mutex_unlock(&dpm_mtx); -} - -EXPORT_SYMBOL_GPL(device_resume); - - -/** - * dpm_power_up - Power on some devices. - * - * Walk the dpm_off_irq list and power each device up. This - * is used for devices that required they be powered down with - * interrupts disabled. As devices are powered on, they are moved - * to the dpm_active list. - * - * Interrupts must be disabled when calling this. - */ - -void dpm_power_up(void) -{ - while(!list_empty(&dpm_off_irq)) { - struct list_head * entry = dpm_off_irq.next; - struct device * dev = to_device(entry); - - list_move_tail(entry, &dpm_off); - resume_device_early(dev); - } -} - - -/** - * device_power_up - Turn on all devices that need special attention. - * - * Power on system devices then devices that required we shut them down - * with interrupts disabled. - * Called with interrupts disabled. - */ - -void device_power_up(void) -{ - sysdev_resume(); - dpm_power_up(); -} - -EXPORT_SYMBOL_GPL(device_power_up); - - diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c deleted file mode 100644 index 204517a..0000000 --- a/drivers/base/power/suspend.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * suspend.c - Functions for putting devices to sleep. - * - * Copyright (c) 2003 Patrick Mochel - * Copyright (c) 2003 Open Source Development Labs - * - * This file is released under the GPLv2 - * - */ - -#include -#include -#include -#include "../base.h" -#include "power.h" - -/* - * The entries in the dpm_active list are in a depth first order, simply - * because children are guaranteed to be discovered after parents, and - * are inserted at the back of the list on discovery. - * - * All list on the suspend path are done in reverse order, so we operate - * on the leaves of the device tree (or forests, depending on how you want - * to look at it ;) first. As nodes are removed from the back of the list, - * they are inserted into the front of their destintation lists. - * - * Things are the reverse on the resume path - iterations are done in - * forward order, and nodes are inserted at the back of their destination - * lists. This way, the ancestors will be accessed before their descendents. - */ - -static inline char *suspend_verb(u32 event) -{ - switch (event) { - case PM_EVENT_SUSPEND: return "suspend"; - case PM_EVENT_FREEZE: return "freeze"; - case PM_EVENT_PRETHAW: return "prethaw"; - default: return "(unknown suspend event)"; - } -} - - -static void -suspend_device_dbg(struct device *dev, pm_message_t state, char *info) -{ - dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event), - ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ? - ", may wakeup" : ""); -} - -/** - * suspend_device - Save state of one device. - * @dev: Device. - * @state: Power state device is entering. - */ - -static int suspend_device(struct device * dev, pm_message_t state) -{ - int error = 0; - - down(&dev->sem); - if (dev->power.power_state.event) { - dev_dbg(dev, "PM: suspend %d-->%d\n", - dev->power.power_state.event, state.event); - } - - if (dev->class && dev->class->suspend) { - suspend_device_dbg(dev, state, "class "); - error = dev->class->suspend(dev, state); - suspend_report_result(dev->class->suspend, error); - } - - if (!error && dev->type && dev->type->suspend) { - suspend_device_dbg(dev, state, "type "); - error = dev->type->suspend(dev, state); - suspend_report_result(dev->type->suspend, error); - } - - if (!error && dev->bus && dev->bus->suspend) { - suspend_device_dbg(dev, state, ""); - error = dev->bus->suspend(dev, state); - suspend_report_result(dev->bus->suspend, error); - } - up(&dev->sem); - return error; -} - - -/* - * This is called with interrupts off, only a single CPU - * running. We can't acquire a mutex or semaphore (and we don't - * need the protection) - */ -static int suspend_device_late(struct device *dev, pm_message_t state) -{ - int error = 0; - - if (dev->bus && dev->bus->suspend_late) { - suspend_device_dbg(dev, state, "LATE "); - error = dev->bus->suspend_late(dev, state); - suspend_report_result(dev->bus->suspend_late, error); - } - return error; -} - -/** - * device_suspend - Save state and stop all devices in system. - * @state: Power state to put each device in. - * - * Walk the dpm_active list, call ->suspend() for each device, and move - * it to the dpm_off list. - * - * (For historical reasons, if it returns -EAGAIN, that used to mean - * that the device would be called again with interrupts disabled. - * These days, we use the "suspend_late()" callback for that, so we - * print a warning and consider it an error). - * - * If we get a different error, try and back out. - * - * If we hit a failure with any of the devices, call device_resume() - * above to bring the suspended devices back to life. - * - */ - -int device_suspend(pm_message_t state) -{ - int error = 0; - - might_sleep(); - mutex_lock(&dpm_mtx); - mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_active) && error == 0) { - struct list_head * entry = dpm_active.prev; - struct device * dev = to_device(entry); - - get_device(dev); - mutex_unlock(&dpm_list_mtx); - - error = suspend_device(dev, state); - - mutex_lock(&dpm_list_mtx); - - /* Check if the device got removed */ - if (!list_empty(&dev->power.entry)) { - /* Move it to the dpm_off list */ - if (!error) - list_move(&dev->power.entry, &dpm_off); - } - if (error) - printk(KERN_ERR "Could not suspend device %s: " - "error %d%s\n", - kobject_name(&dev->kobj), error, - error == -EAGAIN ? " (please convert to suspend_late)" : ""); - put_device(dev); - } - mutex_unlock(&dpm_list_mtx); - if (error) - dpm_resume(); - - mutex_unlock(&dpm_mtx); - return error; -} - -EXPORT_SYMBOL_GPL(device_suspend); - -/** - * device_power_down - Shut down special devices. - * @state: Power state to enter. - * - * Walk the dpm_off_irq list, calling ->power_down() for each device that - * couldn't power down the device with interrupts enabled. When we're - * done, power down system devices. - */ - -int device_power_down(pm_message_t state) -{ - int error = 0; - struct device * dev; - - while (!list_empty(&dpm_off)) { - struct list_head * entry = dpm_off.prev; - - dev = to_device(entry); - error = suspend_device_late(dev, state); - if (error) - goto Error; - list_move(&dev->power.entry, &dpm_off_irq); - } - - error = sysdev_suspend(state); - Done: - return error; - Error: - printk(KERN_ERR "Could not power down device %s: " - "error %d\n", kobject_name(&dev->kobj), error); - dpm_power_up(); - goto Done; -} - -EXPORT_SYMBOL_GPL(device_power_down); - -void __suspend_report_result(const char *function, void *fn, int ret) -{ - if (ret) { - printk(KERN_ERR "%s(): ", function); - print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); - printk("%d\n", ret); - } -} -EXPORT_SYMBOL_GPL(__suspend_report_result); -- cgit v0.10.2