Linuxのueventの挙動がversionによって違う

Linux Kernelからの情報をPF_NETLINK、NETLINK_KOBJECT_UEVENTのソケットで待ち受けるプログラムを実装したのですが、開発機と実機で挙動が違い、調査を行ったので備忘録としてまとめておきます。

結論から言えば、タイトル通りLinux Kernelのversionの違いが原因でした(開発機と実機でversion合わせるのは無理なのです…)。

開発機、実機はそれぞれ以下のversion、archでした。
・開発機=2.6.32-34-generic(x86)
・実機=2.6.37(arm)

開発機で開発し動作確認していたプログラムの概要は、プログラム起動時に/sys/devicesディレクトリ配下にあるueventというファイルにアクセスし、’ ‘(スペース)を書き込むことにより、kernelから通知される情報をソケットを通じて取得するというものでした。

このプログラムは、開発機では全く問題なく動作しましたが、実際に実機で実行してみるとkernel側から情報が全く通知されないという問題が発生しました。

そこで、実機のログを確認すると、以下のようなメッセージが非常に多く出力されていました。

(中略)
pci0000:00: uevent: unknown action-string
pci_bus 0000:00: uevent: unknown action-string
pci 0000:00:00.0: uevent: unknown action-string
pci 0000:01:00.0: uevent: unknown action-string
pci 0000:02:01.0: uevent: unknown action-string
ath9k 0000:03:00.0: uevent: unknown action-string
ieee80211 phy0: uevent: unknown action-string
(中略)

このメッセージを調べていくと、drivers/base/core.c内のstore_uevent関数の実装が2.6.32と2.6.37で異なっていました。

2.6.32-drivers/base/core.c-store_uevent関数

static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
{
        enum kobject_action action;

        if (kobject_action_type(buf, count, &action) == 0) {
                kobject_uevent(&dev->kobj, action);
                goto out;
        }

        dev_err(dev, "uevent: unsupported action-string; this will "
                     "be ignored in a future kernel version\n");
        kobject_uevent(&dev->kobj, KOBJ_ADD);
out:
        return count;
}

2.6.37-drivers/base/core.c-store_uevent関数

static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
{
        enum kobject_action action;

        if (kobject_action_type(buf, count, &action) == 0)
                kobject_uevent(&dev->kobj, action);
        else
                dev_err(dev, "uevent: unknown action-string\n");
        return count;
}

それぞれの関数内で呼ばれているkobject_action_type関数は、以下の配列の中からbufの内容と一致するものを探し、一致するものがあれば0を返すというものです。

static const char *kobject_actions[] = {
        [KOBJ_ADD] =            "add",
        [KOBJ_REMOVE] =         "remove",
        [KOBJ_CHANGE] =         "change",
        [KOBJ_MOVE] =           "move",
        [KOBJ_ONLINE] =         "online",
        [KOBJ_OFFLINE] =        "offline",
};

実装したプログラムは前述したように、ueventに対して’ ‘(スペース)を書き込むようにしていました。
2.6.32では一致するものが無かった場合、’add’が書き込まれたものとしてkobject_uevent関数を実行するように実装されていますが、2.6.37ではエラーメッセージを出力して終了するように実装されています。

このため、開発機では想定通りに動作するが、実機では動作せずにエラーログが出力されるという現象が発生したようです。
実機のkernelに合わせるため、ueventに対して’add’を書き込むように実装変更したところ、開発機と実機で動作するようになりました。

store_uevent関数は、2.6.33と2.6.34の間で変更されているようなので、同様の現象に悩まされている場合は参考にしてみてください。

One Comment

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*