Zarządzanie informacjami o urządzeniach (sysfs i hotplug)


przydatne terminy:

podsystem (subsystem) - główne spojrzenie na architekturę systemu.

Podsystemy zawierają urządzenia (hierarchiczny widok na wszystkie urządzenia w systemie), szyny (widok na szyny), klasy (urządzenia przyporządkowane do klas), net (sieć) (podsystem sieciowy) i inne. Lepszym sposobem myślenia o podsystemach, jest szczegółowy widok na strukturę modelu urządzeń niż jako na fizyczne komponenty systemu. Te same obiekty (zazwyczaj urządzenia) ukazują się w wielu podsystemach, ale są inaczej zorganizowane.
podsystemy są reprezentowane przez bardzo proste struktury:
struct subsystem {
                  struct kset kset;
                  struct rw_semaphore rwsem;
        };

Unified device model

Dużą zmianą w nowym kernelu jest wprowadzenie Unified device model - ujednolicony model urządzenia. Model urządzenia reprezentuje całkowitą strukturę urządzenia i powłokę systemu poprzez utrzymywanie struktur danych urządzenia. Model kontroluje m.in:
Model ten pozwala na ujednolicenie sterowników, dzięki czemu łatwiejsze jest ich pisanie, a także korzystanie z nich!

Kobjects (struct kobject):

kobjects to prosta reprezentacja danych istotnych dla każdego obiektu w systemie. Kobjekty zawierają atrybuty, które wydaje się, że większość obiektów systemu będzie potrzebować np.: nazwę, licznik odwołań, rodzica, typ, zazwyczaj swoją reprezentację w systemie sysfs. Prawie każdy obiekt w modelu urządzeń ma swój kobject, gdzieś głęboko w systemie.
Kset jest zbiorem kobjectów tego samego typu. Kobjecty występują w ksetach. Ksety kontrolują m.in. jak system odpowiada na zdarzenia typu hotplug (o tym później). Ksety i Kobjecty tworzą razem niejako spoiwo sklejające strukturę modelu urządzeń.
Ksety są zbiorami przypisanymi do odpowiednich podsystemów - struktura subsystem.
A więc ogólnie wygląda to tak:
Struktura kobject pobrana z jądra 2.6.5 z pliku .

struct kobject {
        char                    * k_name;              
        char                    name[KOBJ_NAME_LEN];
        atomic_t                refcount;
        struct list_head        entry;
        struct kobject          * parent;
        struct kset             * kset;
        struct kobj_type        * ktype;
        struct dentry           * dentry;
};

       struct kobj_type {
              void (*release)(struct kobject *);       /* wskaznik na funkcję wywoływaną, kiedy urządzenie jest usuwane - licznik count=0 */
              struct sysfs_ops        * sysfs_ops;  /* te pola kontrolują reprezentację obiektu w sysfs */
              struct attribute        ** default_attrs;
       };
Zobaczmy to na przykładzie prostego sterownika znakowego:

struct cdev {
       struct kobject kobj;
       struct module *owner;
       struct file_operations *ops;
       struct list_head list;
};
aby dostać się do struktury cdev mając wskaźnik do struktury kobject danego urządzenia powinniśmy użyć zdefiniowanego w <linux/kernel.h> makra container_of() w ten sposób:
struct cdev *device = container_of(kp, struct cdev, kobj); gdzie: Oczywiście każde urządzenie musi być zainicjowane i dodane do struktur systemowych. Służą do tego funkcje:
void kobject_init(struct kobject *kobj);
oraz
int kobject_set_name(struct kobject *kobj, const char *format, ...); - wywołanie podobne do printk
należy także ustawić pola:

               struct kobject          * parent;       /* jesli ustawimy na null, to podczas dodawania do kset zostanie to pole zmienione, na główny kobject dla danego kset'u */
              struct kset             * kset;       /* kset, do ktorego należy urządzenie */
              struct kobj_type        * ktype;
              struct dentry           * dentry;
a następnie dodać do systemu nasze urządzenie:
int kobject_add(struct kobject *kobj);
Aby je potem usunąć korzystamy z:
void kobject_del(struct kobject *kobj);

Sysfs

Sysfs jest jakby wizualną reprezentacją urządzeń w systemie.
Sysfs jest zwykle zamontowany na /sys. "Główne" katalogi w /sys odpowiadają za podsystemy.
Pełen model steroników można zobaczyć przeglądając katalogi odpowiedzialne za podsystemy.
Przykład:
główny dysk IDE w systemi będzie widoczny jako:
/sys/devices/pci0/00:11.1/ide0/0.0
ale jego sterownik będzie widoczny także w podsystemach jako linki symboliczne:
/sys/block/hda/device
/sys/bus/ide/devices/0.0

dodatkowo kontroler IDE będzie widoczny jako:
/sys/bus/pci/devices/0.11.1
/sys/bus/pci/drivers/VIA IDE/00:11.1

Przykładowa struktura sysfs: (źródło: http://lwn.net/Articles/31511/)

/sys
|-- block
|   |-- fd0
|   |   |-- dev
|   |   |-- iosched
|   |   |   |-- fifo_batch
|   |   |   |-- front_merges
|   |   |   |-- read_expire
|   |   |   |-- write_expire
|   |   |   `-- writes_starved
|   |   |-- range
|   |   |-- size
|   |   `-- stat
|   `-- hda
|       |-- dev
|       |-- device -> ../../devices/pci0/00:11.1/ide0/0.0
|       |-- hda1
|       |   |-- dev
|       |   |-- size
|       |   |-- start
|       |   `-- stat
|       |-- hda2
|       |   |-- dev
|       |   |-- size
|       |   |-- start
|       |   `-- stat
|       |-- hda3
|       |   |-- dev
|       |   |-- size
|       |   |-- start
|       |   `-- stat
|       |-- iosched
|       |   |-- fifo_batch
|       |   |-- front_merges
|       |   |-- read_expire
|       |   |-- write_expire
|       |   `-- writes_starved
|       |-- range
|       |-- size
|       `-- stat
|-- bus
|   |-- ide
|   |   |-- devices
|   |   |   |-- 0.0 -> ../../../devices/pci0/00:11.1/ide0/0.0
|   |   |   `-- 1.0 -> ../../../devices/pci0/00:11.1/ide1/1.0
|   |   `-- drivers
|   |       `-- ide-disk
|   |-- pci
|   |   |-- devices
|   |   |   |-- 00:00.0 -> ../../../devices/pci0/00:00.0
|   |   |   |-- 00:01.0 -> ../../../devices/pci0/00:01.0
|   |   |   |-- 00:05.0 -> ../../../devices/pci0/00:05.0
|   |   |   |-- 00:09.0 -> ../../../devices/pci0/00:09.0
|   |   |   |-- 00:09.1 -> ../../../devices/pci0/00:09.1
|   |   |   |-- 00:09.2 -> ../../../devices/pci0/00:09.2
|   |   |   |-- 00:0c.0 -> ../../../devices/pci0/00:0c.0
|   |   |   |-- 00:11.0 -> ../../../devices/pci0/00:11.0
|   |   |   |-- 00:11.1 -> ../../../devices/pci0/00:11.1
|   |   |   |-- 00:11.2 -> ../../../devices/pci0/00:11.2
|   |   |   |-- 00:11.3 -> ../../../devices/pci0/00:11.3
|   |   |   `-- 01:00.0 -> ../../../devices/pci0/00:01.0/01:00.0
|   |   `-- drivers
|   |       |-- AEC62xx IDE
|   |       |-- ALI15x3 IDE
|   |       |-- AMD IDE
|   |       |-- CMD64x IDE
|   |       |-- Cypress IDE
|   |       |-- HPT34x IDE
|   |       |-- HPT366 IDE
|   |       |-- PIIX IDE
|   |       |-- RZ1000 IDE
|   |       |-- SIS IDE
|   |       |-- SLC90e66 IDE
|   |       |-- Serverworks IDE
|   |       |-- VIA IDE
|   |       |   `-- 00:11.1 -> ../../../../devices/pci0/00:11.1
|   |       |-- eepro100
|   |       |   `-- 00:0c.0 -> ../../../../devices/pci0/00:0c.0
|   |       `-- parport_pc
|   |-- platform
|   |   |-- devices
|   |   |   `-- floppy0 -> ../../../devices/legacy/floppy0
|   |   `-- drivers
|   |-- pnp
|   |   |-- devices
|   |   `-- drivers
|   |       |-- parport_pc
|   |       `-- system
|   |-- system
|   |   |-- devices
|   |   |   |-- cpu0 -> ../../../devices/sys/cpu0
|   |   |   |-- pic0 -> ../../../devices/sys/pic0
|   |   |   |-- rtc0 -> ../../../devices/sys/rtc0
|   |   |   `-- timer0 -> ../../../devices/sys/timer0
|   |   `-- drivers
|   |       |-- cpu
|   |       |   `-- cpu0 -> ../../../../devices/sys/cpu0
|   |       |-- pic
|   |       |   `-- pic0 -> ../../../../devices/sys/pic0
|   |       `-- timer
|   |           `-- timer0 -> ../../../../devices/sys/timer0
|   `-- usb
|       |-- devices
|       `-- drivers
|           |-- hub
|           |-- usb
|           `-- usbfs
|-- class
|   |-- cpu
|   |   `-- cpu0
|   |       `-- device -> ../../../devices/sys/cpu0
|   |-- input
|   `-- tty
|-- devices
|   |-- legacy
|   |   |-- floppy0
|   |   |   |-- name
|   |   |   `-- power
|   |   |-- name
|   |   `-- power
|   |-- pci0
|   |   |-- 00:00.0
|   |   |   |-- class
|   |   |   |-- device
|   |   |   |-- irq
|   |   |   |-- name
|   |   |   |-- power
|   |   |   |-- resource
|   |   |   |-- subsystem_device
|   |   |   |-- subsystem_vendor
|   |   |   `-- vendor
|   |   |-- 00:01.0
|   |   |   |-- 01:00.0
|   |   |   |   |-- class
|   |   |   |   |-- device
|   |   |   |   |-- irq
|   |   |   |   |-- name
|   |   |   |   |-- power
|   |   |   |   |-- resource
|   |   |   |   |-- subsystem_device
|   |   |   |   |-- subsystem_vendor
|   |   |   |   `-- vendor
|   |   |   |-- class
|   |   |   |-- device
|   |   |   |-- irq
|   |   |   |-- name
|   |   |   |-- power
|   |   |   |-- resource
|   |   |   |-- subsystem_device
|   |   |   |-- subsystem_vendor
|   |   |   `-- vendor
|   |   |-- 00:05.0
|   |   |   |-- class
|   |   |   |-- device
|   |   |   |-- irq
|   |   |   |-- name
|   |   |   |-- power
|   |   |   |-- resource
|   |   |   |-- subsystem_device
|   |   |   |-- subsystem_vendor
|   |   |   `-- vendor
|   |   |-- 00:09.0
|   |   |   |-- class
|   |   |   |-- device
|   |   |   |-- irq
|   |   |   |-- name
|   |   |   |-- power
|   |   |   |-- resource
|   |   |   |-- subsystem_device
|   |   |   |-- subsystem_vendor
|   |   |   `-- vendor
|   |   |-- 00:09.1
|   |   |   |-- class
|   |   |   |-- device
|   |   |   |-- irq
|   |   |   |-- name
|   |   |   |-- power
|   |   |   |-- resource
|   |   |   |-- subsystem_device
|   |   |   |-- subsystem_vendor
|   |   |   `-- vendor
|   |   |-- 00:09.2
|   |   |   |-- class
|   |   |   |-- device
|   |   |   |-- irq
|   |   |   |-- name
|   |   |   |-- power
|   |   |   |-- resource
|   |   |   |-- subsystem_device
|   |   |   |-- subsystem_vendor
|   |   |   `-- vendor
|   |   |-- 00:0c.0
|   |   |   |-- class
|   |   |   |-- device
|   |   |   |-- irq
|   |   |   |-- name
|   |   |   |-- power
|   |   |   |-- resource
|   |   |   |-- subsystem_device
|   |   |   |-- subsystem_vendor
|   |   |   `-- vendor
|   |   |-- 00:11.0
|   |   |   |-- class
|   |   |   |-- device
|   |   |   |-- irq
|   |   |   |-- name
|   |   |   |-- power
|   |   |   |-- resource
|   |   |   |-- subsystem_device
|   |   |   |-- subsystem_vendor
|   |   |   `-- vendor
|   |   |-- 00:11.1
|   |   |   |-- class
|   |   |   |-- device
|   |   |   |-- ide0
|   |   |   |   |-- 0.0
|   |   |   |   |   |-- block -> ../../../../../block/hda
|   |   |   |   |   |-- name
|   |   |   |   |   `-- power
|   |   |   |   |-- name
|   |   |   |   `-- power
|   |   |   |-- ide1
|   |   |   |   |-- 1.0
|   |   |   |   |   |-- name
|   |   |   |   |   `-- power
|   |   |   |   |-- name
|   |   |   |   `-- power
|   |   |   |-- irq
|   |   |   |-- name
|   |   |   |-- power
|   |   |   |-- resource
|   |   |   |-- subsystem_device
|   |   |   |-- subsystem_vendor
|   |   |   `-- vendor
|   |   |-- 00:11.2
|   |   |   |-- class
|   |   |   |-- device
|   |   |   |-- irq
|   |   |   |-- name
|   |   |   |-- power
|   |   |   |-- resource
|   |   |   |-- subsystem_device
|   |   |   |-- subsystem_vendor
|   |   |   `-- vendor
|   |   |-- 00:11.3
|   |   |   |-- class
|   |   |   |-- device
|   |   |   |-- irq
|   |   |   |-- name
|   |   |   |-- power
|   |   |   |-- resource
|   |   |   |-- subsystem_device
|   |   |   |-- subsystem_vendor
|   |   |   `-- vendor
|   |   |-- name
|   |   `-- power
|   `-- sys
|       |-- cpu0
|       |   |-- name
|       |   `-- power
|       |-- name
|       |-- pic0
|       |   |-- name
|       |   `-- power
|       |-- power
|       |-- rtc0
|       |   |-- name
|       |   `-- power
|       `-- timer0
|           |-- name
|           `-- power
|-- firmware
|   `-- acpi
|       `-- namespace
|           `-- ACPI
|               |-- CPU0
|               |-- PWRF
|               `-- _SB
|                   |-- LNKA
|                   |-- LNKB
|                   |-- LNKC
|                   |-- LNKD
|                   |-- LNKE
|                   |-- MEM1
|                   |-- PCI0
|                   |   |-- IDE0
|                   |   |   |-- CHN0
|                   |   |   |   |-- DRV0
|                   |   |   |   `-- DRV1
|                   |   |   `-- CHN1
|                   |   |       |-- DRV0
|                   |   |       `-- DRV1
|                   |   |-- PCI1
|                   |   |-- PX40
|                   |   |   |-- COPR
|                   |   |   |-- DMA1
|                   |   |   |-- ECP
|                   |   |   |-- FDC0
|                   |   |   |-- IRDA
|                   |   |   |-- LPT
|                   |   |   |-- MSRD
|                   |   |   |-- PIC
|                   |   |   |-- PS2K
|                   |   |   |-- PS2M
|                   |   |   |-- PSMR
|                   |   |   |-- RTC
|                   |   |   |-- SBIO
|                   |   |   |-- SDRD
|                   |   |   |-- SPKR
|                   |   |   |-- SYS1
|                   |   |   |-- SYS2
|                   |   |   |-- SYS3
|                   |   |   |-- TMR
|                   |   |   |-- UAR1
|                   |   |   `-- UAR2
|                   |   |-- USB0
|                   |   `-- USB1
|                   `-- PWRB
|-- fs
|   |-- autofs
|   |-- bdev
|   |-- binfmt_misc
|   |-- devpts
|   |-- eventpollfs
|   |-- ext2
|   |-- ext3
|   |-- futexfs
|   |-- iso9660
|   |-- nfs
|   |-- nfs4
|   |-- nfsd
|   |-- pipefs
|   |-- proc
|   |-- ramfs
|   |-- rootfs
|   |-- rpc_pipefs
|   |-- sockfs
|   |-- sysfs
|   |-- tmpfs
|   |-- usbdevfs
|   `-- usbfs
`-- net
    `-- eth0

Hotplug

W jądrze 2.6, hotplug został w całości zintegrowany z modelem urządzeń, dlatego dowolna szyna lub klasa mogą raportować zdarzenia hotplug kiedy urządzenia są dodawane bądź usuwane. Dla użytkownika oznacza to tyle, że podłączenie myszki na USB spowoduje automatyczne jej wykrycie i włączenie odpowiedniego sterownika. Ten mechanizm działa także dla PCI :)
Prześledźmy co się dzieje z systemem, kiedy podłączymy do komputera napęd USB.

Literatura:


Powrót

Autor: Piotr Włodarczyk, pw209226@students.mimuw.edu.pl