本文主要是介绍kobject创建文件夹和文件测试。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
kobject创建目录。的本质是通过sysfs创建的。通过kernfs_node *ns来建立关系。
kobject_create_and_add
最简单方式创建kobject。内部创建对象。参数为名字,如果parent为空,则创建在/sys/目录下。否则为parent的子目录
struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
{struct kobject *kobj;int retval;kobj = kobject_create(); //kobject_initif (!kobj)return NULL;retval = kobject_add(kobj, parent, "%s", name);if (retval) {pr_warn("%s: kobject_add error: %d\n", __func__, retval);kobject_put(kobj);kobj = NULL;}return kobj;
}
kobject_create:内部自动关联dynamic_kobj_type,有代码可以看出,sysfs_ops的show/store函数会将动态将attribute转换成kobj_attribute。并找到show/store方法运行,方便调用用户的函数。
struct sysfs_ops {ssize_t (*show)(struct kobject *, struct attribute *, char *);ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
};
继续
struct kobject *kobject_create(void)
{struct kobject *kobj;kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);if (!kobj)return NULL;kobject_init(kobj, &dynamic_kobj_ktype);return kobj;
}static struct kobj_type dynamic_kobj_ktype = {.release = dynamic_kobj_release,.sysfs_ops = &kobj_sysfs_ops,
};
继续
结构体:attr后面是show/store函数指针
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);
};/* default kobject attribute operations */
static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,char *buf)
{struct kobj_attribute *kattr;ssize_t ret = -EIO;kattr = container_of(attr, struct kobj_attribute, attr);if (kattr->show)ret = kattr->show(kobj, kattr, buf);return ret;
}static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,const char *buf, size_t count)
{struct kobj_attribute *kattr;ssize_t ret = -EIO;kattr = container_of(attr, struct kobj_attribute, attr);if (kattr->store)ret = kattr->store(kobj, kattr, buf, count);return ret;
}const struct sysfs_ops kobj_sysfs_ops = {.show = kobj_attr_show,.store = kobj_attr_store,
};
kobject_init_and_add
方式二:自己创建kobject和kobj_type 等。这种方式给用户自由,比如用户自己定义了attribute结果。那么如果用户需要自定义类似kobj_attribute的结构体就需要自己实现sysfs_os中的show/store函数。
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,struct kobject *parent, const char *fmt, ...)
{va_list args;int retval;kobject_init(kobj, ktype);va_start(args, fmt);retval = kobject_add_varg(kobj, parent, fmt, args);va_end(args);return retval;
}
例子:
#include <linux/init.h>
#include <linux/module.h>MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("colorfulshark@hotmail.com");static struct kobject mykobj;//自己创建的show函数,简单实使用没有再调用自己的类attri后面的其他方法。
static ssize_t fw_cfg_sysfs_attr_show(struct kobject *kobj, struct attribute *a,char *buf)
{dump_stack();return sprintf(buf, "fw_cfg_sysfs_attr_show\n");
}//自己创建的sysfs_ops
static const struct sysfs_ops fw_cfg_sysfs_attr_ops = {.show = fw_cfg_sysfs_attr_show,
};//自创建的kobj_type
static struct kobj_type fw_cfg_sysfs_entry_ktype = {// .default_attrs = fw_cfg_sysfs_entry_attrs,.sysfs_ops = &fw_cfg_sysfs_attr_ops,//.release = fw_cfg_sysfs_release_entry,
};static struct kobject *fw_cfg_top_ko;static ssize_t fw_cfg_showrev(struct kobject *k, struct attribute *a, char *buf)
{dump_stack();return sprintf(buf, "hello jaon\n");
}static const struct {struct attribute attr;ssize_t (*show)(struct kobject *k, struct attribute *a, char *buf);
} fw_cfg_rev_attr = {.attr = { .name = "rev", .mode = S_IRUSR },.show = fw_cfg_showrev,
};
static int xxx_init(void)
{ dump_stack(); fw_cfg_top_ko = kobject_create_and_add("test1", NULL);sysfs_create_file(fw_cfg_top_ko, &fw_cfg_rev_attr.attr); kobject_init_and_add(&mykobj, &fw_cfg_sysfs_entry_ktype,NULL, "subxx1");sysfs_create_file(&mykobj,&fw_cfg_rev_attr.attr); //这里我复用了fw_cfg_rev_attr.attr 这个attribute。当然也可以自定义一个,在show中用container_of 找到自己定义的show函数指针。printk(KERN_ALERT "module xxx init\n");return 0;
} static void xxx_exit(void)
{ printk(KERN_ALERT "module xxx exit\n");
}
module_init(xxx_init);
module_exit(xxx_exit);
方式1:
[root@localhost ~]# cat /sys/kernel/kexec_crash_size
[ 1406.506644] CPU: 4 PID: 1218 Comm: cat Not tainted 4.19.0-fix-full-10+ #18
[ 1406.517365] Hardware name: PHYTIUM LTD D2000/D2000, BIOS
[ 1406.526003] Call trace:
[ 1406.531549] dump_backtrace+0x0/0x1b8
[ 1406.538233] show_stack+0x24/0x30
[ 1406.544511] dump_stack+0x90/0xb4
[ 1406.550767] kexec_crash_size_show+0x1c/0x48
[ 1406.557975] kobj_attr_show+0x14/0x28
[ 1406.564573] sysfs_kf_seq_show+0x9c/0x138
[ 1406.571518] kernfs_seq_show+0x44/0x50
[ 1406.578210] seq_read+0xd4/0x4a8
[ 1406.584379] kernfs_fop_read+0x16c/0x218
[ 1406.591254] __vfs_read+0x60/0x188
[ 1406.597612] vfs_read+0x94/0x150
[ 1406.603770] ksys_read+0x6c/0xd8
[ 1406.609957] __arm64_sys_read+0x24/0x30
[ 1406.616751] el0_svc_handler+0x84/0x140
[ 1406.623552] el0_svc+0x8/0xc
方式2:
[217963.967082] show_stack+0x52/0x58
[217963.967086] dump_stack_lvl+0x4a/0x5f
[217963.967089] dump_stack+0x10/0x12
[217963.967093] fw_cfg_sysfs_attr_show+0x13/0x2b [test] //这里直接调用
[217963.967095] sysfs_kf_seq_show+0xa1/0x100
[217963.967098] kernfs_seq_show+0x27/0x30
[217963.967100] seq_read_iter+0x120/0x4b0
[217963.967117] ? do_anonymous_page+0x1f5/0x3b0
[217963.967119] kernfs_fop_read_iter+0x2c/0x30
[217963.967121] new_sync_read+0x110/0x190
[217963.967124] vfs_read+0xff/0x1a0
[217963.967126] ksys_read+0x67/0xe0
[217963.967128] __x64_sys_read+0x19/0x20
[217963.967129] do_syscall_64+0x5c/0xc0
[217963.967130] ? exit_to_user_mode_prepare+0x37/0xb0
[217963.967133] ? irqentry_exit_to_user_mode+0x9/0x20
[217963.967135] ? irqentry_exit+0x19/0x30
[217963.967136] ? exc_page_fault+0x89/0x160
[217963.967138] ? asm_exc_page_fault+0x8/0x30
[217963.967623] entry_SYSCALL_64_after_hwframe+0x44/0xae
kset_create_and_add
kset结构体:包含一个kobject,也会创建目录,将相同类型的kobject进行关联。
//struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
struct kset {struct list_head list; //链表,spinlock_t list_lock;struct kobject kobj; //包含一个完整kobjectconst struct kset_uevent_ops *uevent_ops;
} __randomize_layout;
struct kset *kset_create_and_add(const char *name,const struct kset_uevent_ops *uevent_ops,struct kobject *parent_kobj)
{struct kset *kset;int error;kset = kset_create(name, uevent_ops, parent_kobj);if (!kset)return NULL;error = kset_register(kset);if (error) {kfree(kset);return NULL;}return kset;
}static struct kset *kset_create(const char *name,const struct kset_uevent_ops *uevent_ops,struct kobject *parent_kobj)
{struct kset *kset;int retval;kset = kzalloc(sizeof(*kset), GFP_KERNEL);if (!kset)return NULL;retval = kobject_set_name(&kset->kobj, "%s", name);if (retval) {kfree(kset);return NULL;}kset->uevent_ops = uevent_ops;kset->kobj.parent = parent_kobj;/** The kobject of this kset will have a type of kset_ktype and belong to* no kset itself. That way we can properly free it when it is* finished being used.*/kset->kobj.ktype = &kset_ktype;kset->kobj.kset = NULL;return kset;
}
如果自己创建的kobject中的kset非NULL,那么在初始化接口kobject_init_and_add->kobject_add_internal:
static int kobject_add_internal(struct kobject *kobj)
{int error = 0;struct kobject *parent;if (!kobj)return -ENOENT;if (!kobj->name || !kobj->name[0]) {WARN(1,"kobject: (%p): attempted to be registered with empty name!\n",kobj);return -EINVAL;}parent = kobject_get(kobj->parent);/* join kset if set, use it as parent if we do not already have one */if (kobj->kset) {if (!parent)parent = kobject_get(&kobj->kset->kobj);kobj_kset_join(kobj); //加入kset的链表kobj->parent = parent;}................
}static void kobj_kset_leave(struct kobject *kobj)
{if (!kobj->kset)return;spin_lock(&kobj->kset->list_lock);list_del_init(&kobj->entry);spin_unlock(&kobj->kset->list_lock);kset_put(kobj->kset);
}
后续通过kset_find_obj函数查找:
struct kobject *kset_find_obj(struct kset *kset, const char *name)
{struct kobject *k;struct kobject *ret = NULL;spin_lock(&kset->list_lock);list_for_each_entry(k, &kset->list, entry) {if (kobject_name(k) && !strcmp(kobject_name(k), name)) {ret = kobject_get_unless_zero(k);break;}}spin_unlock(&kset->list_lock);return ret;
}
创建文件目录和文件(attribute)的本质:
kobject_add_internalcreate_dir(kobj)sysfs_create_dir_ns(kobj, kobject_namespace(kobj)); //fs/sysfs/dir.c kernfs_create_dir_ns //fs/kernfs/dir.c 创建 kernfs_node * kn目录,union配置为kernfs_elem_dirkernfs_new_node kernfs_add_one 设置kobject->sd为kn populate_dir(kobj); //为默认的default_attrs[]创建文件属性sysfs_create_file(kobj, attr); //循环调用sysfs_create_file_ns(kobj, attr, NULL);sysfs_add_file_mode_ns //fs/sysfs/file.c__kernfs_create_file //fs/kernfs/file.c 设置union的kernfs_elem_attrkernfs_new_node //创建kernfs_node *kn ,以kobject->sd为parentkernfs_add_one
amdgpu驱动中在/sys/bus/pci/devices/0000:0f:00.0/下面创建vram相关的属性文件:
root@wzm-phytium-d2000:/sys/bus/pci/devices/0000:0f:00.0# ls mem_info_*
mem_info_gtt_total mem_info_preempt_used mem_info_vis_vram_used mem_info_vram_used
mem_info_gtt_used mem_info_vis_vram_total mem_info_vram_total mem_info_vram_vendor
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
/*** DOC: mem_info_vram_total** The amdgpu driver provides a sysfs API for reporting current total VRAM* available on the device* The file mem_info_vram_total is used for this and returns the total* amount of VRAM in bytes*/
static ssize_t amdgpu_mem_info_vram_total_show(struct device *dev,struct device_attribute *attr, char *buf)
{struct drm_device *ddev = dev_get_drvdata(dev);struct amdgpu_device *adev = drm_to_adev(ddev);return snprintf(buf, PAGE_SIZE, "%llu\n", adev->gmc.real_vram_size);
}/*** DOC: mem_info_vis_vram_total** The amdgpu driver provides a sysfs API for reporting current total* visible VRAM available on the device* The file mem_info_vis_vram_total is used for this and returns the total* amount of visible VRAM in bytes*/
static ssize_t amdgpu_mem_info_vis_vram_total_show(struct device *dev,struct device_attribute *attr, char *buf)
{struct drm_device *ddev = dev_get_drvdata(dev);struct amdgpu_device *adev = drm_to_adev(ddev);return snprintf(buf, PAGE_SIZE, "%llu\n", adev->gmc.visible_vram_size);
}static DEVICE_ATTR(mem_info_vram_total, S_IRUGO,amdgpu_mem_info_vram_total_show, NULL);
static DEVICE_ATTR(mem_info_vis_vram_total, S_IRUGO,amdgpu_mem_info_vis_vram_total_show,NULL);
static DEVICE_ATTR(mem_info_vram_used, S_IRUGO,amdgpu_mem_info_vram_used_show, NULL);
static DEVICE_ATTR(mem_info_vis_vram_used, S_IRUGO,amdgpu_mem_info_vis_vram_used_show, NULL);
static DEVICE_ATTR(mem_info_vram_vendor, S_IRUGO,amdgpu_mem_info_vram_vendor, NULL);static const struct attribute *amdgpu_vram_mgr_attributes[] = {&dev_attr_mem_info_vram_total.attr,&dev_attr_mem_info_vis_vram_total.attr,&dev_attr_mem_info_vram_used.attr,&dev_attr_mem_info_vis_vram_used.attr,&dev_attr_mem_info_vram_vendor.attr,NULL
};int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
{struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;struct ttm_resource_manager *man = &mgr->manager;int ret;ttm_resource_manager_init(man, adev->gmc.real_vram_size >> PAGE_SHIFT);man->func = &amdgpu_vram_mgr_func;drm_mm_init(&mgr->mm, 0, man->size);spin_lock_init(&mgr->lock);/* Add the two VRAM-related sysfs files */ret = sysfs_create_files(&adev->dev->kobj, amdgpu_vram_mgr_attributes);if (ret)DRM_ERROR("Failed to register sysfs\n");ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);ttm_resource_manager_set_used(man, true);return 0;
}
这篇关于kobject创建文件夹和文件测试。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!