/var/log/messages

debugging with sixth sense

Device_add という手続き

drivers/base/core.c にて定義。device_create_groups_vargs 手続きから呼び出されています。struct device なオブジェクトの初期化をして device_add に渡されてます。

で、直前エントリにて dpm_sysfs_add が核心? とかって書いたのですが、そっちではなくて device_create_file が、な模様。手続き定義のコメントが以下。

 * device_create_file - create sysfs attribute file for device.

ここから sysfs_create_file という手続きを呼び出していますね。どんどん掘ります。

  • device_create_file
  • sysfs_create_file
  • sysfs_create_file_ns
  • sysfs_add_file_mode_ns

ここから _kernfs_create_file という手続きが呼び出されています。む、kernfs て何だろ。

というか

kobject_add という手続きを掘ってみたあたりでも sysfs を云々してる箇所あり。むむむ。

結論

まず、デバイスドライバと sysfs との関係をきちんと理解できてない。そこからなのかどうか。

kernel object って何だ

sysfs is a mechanism for representing kernel objects, their attributes, and their relationships with each other. って記述あり。

  • Kernel Objects は Directory として
  • Object Attributes は Regular File として
  • Object Relationships は Symbolic Link として

って記述もありますね。そういった意味では /sys/class/gpio というディレクトリが作られるのはいつなんだ、という疑問もあり。

でもこれってある意味それ以前の話だったりするのかどうか。

順番てきに、gpio なデバイスを発見しているのであれば

  • /sys/class/gpio ディレクトリ作る
  • /sys/class/gpio/gpiochip0 ディレクトリ作る
  • /sys/class/gpio/export および /sys/class/gpio/unexport 作る

までが初期処理であって、export に番号書き込んで始めて

  • /sys/class/gpio/gpio18

みたいなディレクトリができて中に direction だの value だのというもろもろの操作のためのファイルが作られるのが筋なのか。

このへん踏まえて見ないと駄目だな。

再読

ということで再度確認を。gpiolib_sysfs_init 手続き見てみるに、先頭で

    status = class_register(&gpio_class);

みたいなことしてます。臭い。

  • __class_register
  • kset_register
  • kobject_add_internal
  • crate_dir

で /sys/class/gpio ができるのかどうか。create_dir 手続きの中で sysfs_create_dir_ns 手続きを呼び出してらっしゃいます。

最初の __class_register で struct subsys_private 型なオブジェクトを作ってて kset_register にはその subsys って属性のみを渡しています。呼び出しまでにそのあたりを弄っていると思われるのが

    error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);

あるいは

#if defined(CONFIG_BLOCK)
    /* let the block class directory show up in the root of sysfs */
    if (!sysfs_deprecated || cls != &block_class)
        cp->subsys.kobj.kset = class_kset;
#else
    cp->subsys.kobj.kset = class_kset;
#endif
    cp->subsys.kobj.ktype = &class_ktype;

というあたりのみ。ちなみに subsys 属性は struct kset 型な模様です。その先で kobj な属性のみを先に渡してるみたいですね。create_dir に至るまでに色々な操作が入っているようです。

  • kset_register にて struct kset なオブジェクトを kset_init しています
  • その中で kobj 属性について kobject_init_internal 手続きを適用
  • kobjext_add_internal にて parent な kobject を取得しようとしている

とりあえず class_register という手続きで gpio というクラスが登録されて /sys/class/gpio というディレクトリができる、という理解で良いかな。

gpiochip_export 手続きか。おそらくここでは gpiochip0 みたいなディレクトリとその中のいくつかのファイルが作られるはず。って /sys/class/gpio/export とか /sys/class/gpio/unexport とかってどうなっているのか。

とは言え、gpio なデバイスが内部的に登録されていないと駄目なのか。ええと掘削ですが

  • gpiolib_sysfs_init
  • gpiochip_export
  • device_create
  • device_create_vargs
  • device_create_groups_vargs
  • device_add

なのか。以下な手続きを呼び出しているのが目に付きます。

  • kobject_add で gpiochip0 なディレクトリが作成される?
  • device_create_file という手続きを呼び出している
  • device_add_class_symlinks という手続きがあるな
  • dvice_add_attrs という手続きがあるな (ここで gpiochip0 の中のファイルが作成される?

device_create_file の中を見てみるに create sysfs attribute file for device. というコメントを発見。ここで export とか unexport とかを、なのかな。

呼び出しが以下になってます。

    error = device_create_file(dev, &dev_attr_uevent);

dev_attr_uevent というのが属性にあたるのかどうか。こいつの出自は何だろ、って定義が driver/base/core.c に無いなorz

これ、compile しないと出てこない、とかってヤツなのかな。device attribute descriptor って何なのか。定義は以下な模様。

/* interface for exporting device attributes */
struct device_attribute {
    struct attribute    attr;
    ssize_t (*show)(struct device *dev, struct device_attribute *attr,
                    char *buf);
    ssize_t (*store)(struct device *dev, struct device_attribute *attr,
                     const char *buf, size_t count);
};

これ、属性なファイルの操作 (読むとか書くとか) に割りあてられた動作を規定しているのか。とは言え、sysfs_create_file に渡しているのは以下らしい。

error = sysfs_create_file(&dev->kobj, &attr->attr);

sysfs_add_file_mode_ns にて show だの store だのな callback を云々していると思われる以下な記述があるのですが

        struct kobject *kobj = parent->priv;
        const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops;

        /* every kobject with an attribute needs a ktype assigned */
        if (WARN(!sysfs_ops, KERN_ERR
                 "missing sysfs attribute operations for kobject: %s\n",
                 kobject_name(kobj)))
            return -EINVAL;

        if (sysfs_ops->show && sysfs_ops->store)
            ops = &sysfs_file_kfops_rw;

例えば sysfs_file_kfops_rw もシンボル未解決。あと、parent とか kobj も微妙に変化しててアレです。device_create_file の呼び出しから見てみるに

device_create_file(dev, &dev_attr_uevent);

で、dev は device_add に渡される struct device なオブジェクトです。そして device_create_file では sysfs_create_file を以下な形で呼び出します。

sysfs_create_file(&dev->kobj, &attr->attr);

kobj という struct kobject 型の属性と attr という struct attribute 型の属性。sysfs_create_file ではある意味そのままですね。

sysfs_create_file_ns(kobj, attr, NULL);

で、sysfs_create_file_ns ですこし代わります。

sysfs_add_file_mode_ns(kobj->sd, attr, false, attr->mode, ns);

sd という属性は struct kernfs_node 型の属性です。ns は三番目の引数で値は NULL ですね。device_create_file に渡している struct device 型のオブジェクトは device_add の先頭らへんで get_device という手続きにより取得しています。ここから確認しないと駄目なのかどうか。

つうか

dev = get_device(dev);

ってどうなのかと。そうか、device_add に渡された struct device オブジェクトは領域確保して初期化されたばかりなのでした。get_device では increment reference count for device. だそうです。以下を戻しています。

return dev ? kobj_to_dev(kobject_get(&dev->kobj)) : NULL;

掘ってみるに確かに reference count らしきものを increment してます。kobj_to_dev は kobj 属性の位置から無理矢理 struct device な先頭アドレスをひり出すアレを使っているのかどうか。

なんか頭がふらふらしてきたのでいったん止めます。

Comments