요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
==========================
The Basic Device Structure
==========================
See the kerneldoc for the struct device.
Programming Interface
~~~~~~~~~~~~~~~~~~~~~
The bus driver that discovers the device uses this to register the
device with the core::
int device_register(struct device * dev);
The bus should initialize the following fields:
- parent
- name
- bus_id
- bus
A device is removed from the core when its reference count goes to
0. The reference count can be adjusted using::
struct device * get_device(struct device * dev);
void put_device(struct device * dev);
get_device() will return a pointer to the struct device passed to it
if the reference is not already 0 (if it's in the process of being
removed already).
A driver can access the lock in the device structure using::
void lock_device(struct device * dev);
void unlock_device(struct device * dev);
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);
};
Attributes of devices can be exported by a device driver through sysfs.
Please see Documentation/filesystems/sysfs.rst for more information
on how sysfs works.
As explained in Documentation/core-api/kobject.rst, device attributes must be
created before the KOBJ_ADD uevent is generated. The only way to realize
that is by defining an attribute group.
Attributes are declared using a macro called DEVICE_ATTR::
#define DEVICE_ATTR(name,mode,show,store)
Example:::
static DEVICE_ATTR(type, 0444, type_show, NULL);
static DEVICE_ATTR(power, 0644, power_show, power_store);
Helper macros are available for common values of mode, so the above examples
can be simplified to:::
static DEVICE_ATTR_RO(type);
static DEVICE_ATTR_RW(power);
This declares two structures of type struct device_attribute with respective
names 'dev_attr_type' and 'dev_attr_power'. These two attributes can be
organized as follows into a group::
static struct attribute *dev_attrs[] = {
&dev_attr_type.attr,
&dev_attr_power.attr,
NULL,
};
static struct attribute_group dev_group = {
.attrs = dev_attrs,
};
static const struct attribute_group *dev_groups[] = {
&dev_group,
NULL,
};
A helper macro is available for the common case of a single group, so the
above two structures can be declared using:::
ATTRIBUTE_GROUPS(dev);
This array of groups can then be associated with a device by setting the
group pointer in struct device before device_register() is invoked::
dev->groups = dev_groups;
device_register(dev);
The device_register() function will use the 'groups' pointer to create the
device attributes and the device_unregister() function will use this pointer
to remove the device attributes.
Word of warning: While the kernel allows device_create_file() and
device_remove_file() to be called on a device at any time, userspace has
strict expectations on when attributes get created. When a new device is
registered in the kernel, a uevent is generated to notify userspace (like
udev) that a new device is available. If attributes are added after the
device is registered, then userspace won't get notified and userspace will
not know about the new attributes.
This is important for device driver that need to publish additional
attributes for a device at driver probe time. If the device driver simply
calls device_create_file() on the device structure passed to it, then
userspace will never be notified of the new attributes.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
기본 device 구조체
1-7`struct device`의 상세 정의는 해당 kerneldoc을 참고합니다.
Programming interface와 lifetime
8-37device를 발견한 bus driver는 다음 함수로 device를 core에 등록합니다.
int device_register(struct device * dev);
bus는 다음 field를 초기화해야 합니다.
- `parent`
- `name`
- `bus_id`
- `bus`
device의 reference count가 0이 되면 core에서 제거됩니다. 다음 함수로 reference count를 조정합니다.
struct device * get_device(struct device * dev);
void put_device(struct device * dev);
reference가 아직 0이 아니라면 `get_device()`는 전달받은 `struct device` pointer를 반환합니다. 이미 제거 과정에 들어가 reference가 0이면 반환하지 않습니다.
driver는 다음 함수로 device 구조체 안의 lock에 접근할 수 있습니다.
void lock_device(struct device * dev);
void unlock_device(struct device * dev);
등록, reference 획득·반납과 제거 조건을 나타냅니다.
Device attribute 구조체와 sysfs
38-54::
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);
};
device driver는 device attribute를 sysfs로 export할 수 있습니다. sysfs 동작에 대한 자세한 내용은 `Documentation/filesystems/sysfs.rst`를 참고합니다.
KOBJ_ADD 이전 attribute 선언
55-68`Documentation/core-api/kobject.rst`의 설명처럼 device attribute는 `KOBJ_ADD` uevent를 생성하기 전에 만들어야 합니다. 이를 실현하는 유일한 방법은 attribute group을 정의하는 것입니다.
attribute는 `DEVICE_ATTR` macro로 선언합니다.
#define DEVICE_ATTR(name,mode,show,store)
예시는 다음과 같습니다.
static DEVICE_ATTR(type, 0444, type_show, NULL);
static DEVICE_ATTR(power, 0644, power_show, power_store);
Helper macro와 attribute group
69-93흔히 사용하는 mode에는 helper macro가 있으므로 앞의 예제를 다음처럼 단순화할 수 있습니다.
static DEVICE_ATTR_RO(type);
static DEVICE_ATTR_RW(power);
이는 각각 `dev_attr_type`과 `dev_attr_power`라는 이름의 `struct device_attribute` 두 개를 선언합니다. 두 attribute는 다음처럼 하나의 group으로 구성할 수 있습니다.
static struct attribute *dev_attrs[] = {
&dev_attr_type.attr,
&dev_attr_power.attr,
NULL,
};
static struct attribute_group dev_group = {
.attrs = dev_attrs,
};
static const struct attribute_group *dev_groups[] = {
&dev_group,
NULL,
};
attribute에서 group array까지의 포함 관계를 정리했습니다.
ATTRIBUTE_GROUPS와 device 등록
94-107group 하나만 사용하는 흔한 경우에는 다음 helper macro로 앞의 두 group 구조체를 선언할 수 있습니다.
ATTRIBUTE_GROUPS(dev);
`device_register()`를 호출하기 전에 `struct device`의 group pointer를 설정해 group array를 device와 연결합니다.
dev->groups = dev_groups;
device_register(dev);
`device_register()`는 `groups` pointer를 사용해 device attribute를 생성하고, `device_unregister()`는 같은 pointer를 사용해 device attribute를 제거합니다.
동적 attribute 생성에 대한 userspace 경고
108-120kernel은 `device_create_file()`과 `device_remove_file()`을 언제든 device에 호출하도록 허용하지만, userspace는 attribute가 생성되는 시점에 엄격한 기대를 가집니다. 새 device가 kernel에 등록되면 udev 같은 userspace에 새 device를 알리는 uevent가 발생합니다.
device 등록 뒤 attribute를 추가하면 userspace에는 별도 notification이 가지 않으므로 새 attribute의 존재를 알지 못합니다. driver probe 시점에 device용 추가 attribute를 공개해야 하는 driver에는 특히 중요합니다. 전달받은 device 구조체에 단순히 `device_create_file()`을 호출하면 userspace는 그 새 attribute를 결코 통지받지 못합니다.
userspace가 attribute를 발견할 수 있는 올바른 등록 순서를 나타냅니다.
요약과 해설
device.rst:1-120device는 bus가 필수 field를 초기화한 뒤 core에 등록하며 reference count로 lifetime을 관리합니다. sysfs attribute는 attribute group으로 구성해 device_register() 전에 dev->groups에 연결해야 KOBJ_ADD uevent를 받은 userspace가 처음부터 완전한 interface를 볼 수 있습니다.