리눅스 커널과 유저 공간 간 데이터 교환을 위한 인터페이스에서 sysfs와 procfs에 대해 알아보도록 하겠습니다. 이 두 가지 인터페이스는 디바이스 드라이버 개발 및 시스템 관리에서 활용됩니다.
mount -t sysfs nodev /sys
struct kobject *kobject_create_and_add(const char *name, struct kobject *parent);
struct kobj_attribute {
struct attribute attr;
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf);
ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count);
};
#define __ATTR(_name, _mode, _show, _store) { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
}
int sysfs_create_file(struct kobject *kobj, const struct attribute *attr);
struct attribute_group {
const char *name;
umode_t (*is_visible)(struct kobject *,
struct attribute *, int);
struct attribute **attrs;
struct bin_attribute **bin_attrs;
};
sysfs_create_group() 함수는 설정된 attribute_group 기반으로 sysfs 파일들을 생성
int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp);
// k_sysfs.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sysfs.h>
#include <linux/kobject.h>
#include <linux/string.h>
static struct kobject *ksys_kobj;
static int sysfs_value;
static ssize_t sysfs_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
pr_info("show attribute: %s\n", attr->attr.name);
return scnprintf(buf, PAGE_SIZE, "%d\n", sysfs_value);
}
static ssize_t sysfs_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val;
if (!sscanf(buf, "%d", &val))
return -EINVAL;
sysfs_value = val;
pr_info("store value: %d\n", val);
return count;
}
static struct kobj_attribute test_attr = __ATTR(test, 0660, sysfs_show, sysfs_store);
static struct attribute *k_attrs[] = {
&test_attr.attr,
NULL,
};
static struct attribute_group k_attr_group = {
.attrs = k_attrs,
};
static int __init k_module_init(void)
{
int err = -1;
pr_info("k_sysfs module init\n");
ksys_kobj = kobject_create_and_add("ksys", kernel_kobj);
if (!ksys_kobj)
return -ENOMEM;
err = sysfs_create_group(ksys_kobj, &k_attr_group);
if (err)
kobject_put(ksys_kobj);
return err;
}
static void __exit k_module_exit(void)
{
if (ksys_kobj)
kobject_put(ksys_kobj);
pr_info("k_sysfs module exit\n");
}
module_init(k_module_init);
module_exit(k_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple sysfs example");
insmod ./k_sysfs.ko
cd /sys/kernel/ksys/
ls
test
cat test
0
echo 23 > test
cat test
23
dmesg | tail -n 2
[ +0.000005] show attribute: test
[ +0.001859] store value: 23
lsmod | grep k_sysfs
k_sysfs 16384 0
rmmod k_sysfs
// k_procfs.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/seq_file.h>
static struct proc_dir_entry *proc_dir;
static struct proc_dir_entry *proc_file;
static int k_proc_show(struct seq_file *m, void *v) {
seq_printf(m, "procfs read function\n");
return 0;
}
static ssize_t k_write(struct file *file, const char __user *user_buffer, size_t count, loff_t *offset)
{
char buf[255];
int to_copy, not_copied, delta;
memset(buf, 0, sizeof(buf));
to_copy = min(count, sizeof(buf));
not_copied = copy_from_user(buf, user_buffer, to_copy);
pr_info("procfs: %s\n", buf);
delta = to_copy - not_copied;
return delta;
}
static int k_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, k_proc_show, NULL);
};
static const struct proc_ops fops = {
.proc_open = k_proc_open,
.proc_read = seq_read,
.proc_write = k_write,
.proc_release = single_release,
};
static int __init k_module_init(void)
{
proc_dir = proc_mkdir("k_proc", NULL);
if (proc_dir == NULL) {
pr_info("procfs_test - Error creating /proc/k_proc\n");
return -ENOMEM;
}
proc_file = proc_create("k_file", 0666, proc_dir, &fops);
if (proc_file == NULL) {
pr_info("procfs_test - Error creating /proc/k_proc/k_file\n");
proc_remove(proc_dir);
return -ENOMEM;
}
return 0;
}
static void __exit k_module_exit(void)
{
proc_remove(proc_file);
proc_remove(proc_dir);
pr_info("k_procfs module exit\n");
}
module_init(k_module_init);
module_exit(k_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple procfs example");