kobject的容器kset与hotplug
PS: linux 无法登录ssh
1.检查linux下sshd 服务 ps -e | grep ssh*
2.重启服务 service /etc/ssh restart
3.ufw disbale 关闭防火墙
struct kset:
struct kset {
struct list_head list;
spinlock_t list_lock;
struct kobject kobj; //kobject 对象容器
const struct kset_uevent_ops *uevent_ops; //kobject 对象发生变化通知用户空间
};
struct kset_uevent_ops {
int (* const filter)(struct kset *kset, struct kobject *kobj); //过滤
const char *(* const name)(struct kset *kset, struct kobject *kobj);
int (* const uevent)(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env *env); //事件
};
操作函数
//初始化kset_init
extern void kset_init(struct kset *kset);
//注册kset
int kset_register(struct kset *k)
kset_init(k); //初始化
err = kobject_add_internal(&k->kobj);//创建目录
kobject_uevent(&k->kobj, KOBJ_ADD); // 如果设置 CONFIG_HOTPLUG ,将向内核发送事件通知用户空间
热插拔过程分析
//注意: kobject对象要支持热插拔必须要有它的容器kset,孤立的kobject是无法支持热插拔的
int kobject_uevent(struct kobject *kobj, enum kobject_action action)
kobject_uevent_env(kobj, action, NULL);
//找到顶层的kset
top_kobj = kobj;
while (!top_kobj->kset && top_kobj->parent)
top_kobj = top_kobj->parent;
//获得顶层的kset的uevent_ops
kset = top_kobj->kset;
uevent_ops = kset->uevent_ops;
//事件是否被顶层过滤
uevent_ops->filter(kset, kobj)
subsystem = uevent_ops->name(kset, kobj);
//准备发送用户空间的消息
env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
retval = add_uevent_var(env, "ACTION=%s", action_string);
retval = uevent_ops->uevent(kset, kobj, env);
#if defined(CONFIG_NET)
//发送 netlink
retval = netlink_broadcast_filtered(uevent_sock, skb,
0, 1, GFP_KERNEL,
kobj_bcast_filter,
kobj);
#else
//call_usermodehelper
linux热插拔的例子
内核:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/slab.h>
static struct kobject * parent = NULL;
static struct kobject * child = NULL;
static struct kset * p_kset =NULL;
static struct attribute child_attr = {
.name = "child_attr",
.mode = S_IRUSR|S_IWUSR,
};
static ssize_t attr_show(struct kobject *kobj, struct attribute *attr,char *buf)
{
printk(KERN_INFO "%s\n",__FUNCTION__);
printk(KERN_INFO"buf[0] = 0x%x",*buf);
return 0;
}
static ssize_t attr_store (struct kobject *kobj,struct attribute *attr,const char *buf, size_t count)
{
unsigned char flag = 0;
printk(KERN_INFO "%s\n",__FUNCTION__);
printk(KERN_INFO"buf[0] = 0x%x",*buf);
flag = *buf-'0';
printk(KERN_INFO"FLAG= %d",flag);
switch(flag)
{
case 0: kobject_uevent(kobj, KOBJ_ADD);break;
case 1: kobject_uevent(kobj, KOBJ_REMOVE);break;
}
return count;
}
static struct sysfs_ops attr_ops ={
.show = attr_show,
.store = attr_store,
};
static struct kobj_type attr_ktype={
.sysfs_ops = &attr_ops,
};
static int __init kobject_test_init(void)
{
printk(KERN_INFO "%s\n",__FUNCTION__);
parent = kobject_create_and_add("pa_obj",NULL);
child = kzalloc(sizeof(*child), GFP_KERNEL);
if (!child)
return NULL;
kobject_init_and_add(child ,&attr_ktype, parent, "pb_obj");
sysfs_create_file(child, &child_attr);
//为 parent 添加一个 kset
p_kset = kset_create_and_add("p_kset", NULL, parent);
//能发生热插拔kobject对象必须属于一个kset
child->kset = p_kset;
return 0;
}
static void __exit kobject_test_exit(void)
{
printk(KERN_INFO "%s\n",__FUNCTION__);
sysfs_remove_file(child, &child_attr);
kset_unregister(p_kset);
kobject_del(child);
kobject_del(parent);
}
module_init(kobject_test_init);
module_exit(kobject_test_exit);
MODULE_AUTHOR("derrick email: kjfure@163.com");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Kobject test Module");
MODULE_ALIAS("Kobject test Module");
用户空间:
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/socket.h>
#include <errno.h>
#include <linux/poll.h>
#define NETLINK_TEST 21
#define MAX_PAYLOAD 1024
int main(int argc, char* argv[])
{
struct sockaddr_nl nls;
struct pollfd pfd;
char buf[512];
memset(&nls,0,sizeof(struct sockaddr_nl));
nls.nl_family=AF_NETLINK;
nls.nl_pid = getpid();
nls.nl_groups=-1;
pfd.events = POLLIN;
pfd.fd = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT);
if(pfd.fd == -1)
{
printf("scoket error\r\n");
return 0;
}
bind(pfd.fd,(void *)&nls,sizeof(struct sockaddr_nl));
while(-1!=poll(&pfd,1,-1))
{
int i,len;
len = recv(pfd.fd,buf,sizeof(buf),MSG_DONTWAIT);
if(len==-1)
{
printf("recv error");
return -1;
}
i=0;
while(i<len){
printf("%s\n",buf+i);
i+=strlen(buf+i)+1;
}
}
printf("poll error\r\n");
return 0;
}
test:
#....# echo '1' > /sys/pa_obj/pb_obj/child_attr
attr_store
buf[0] = 0x31
FLAG= 1remove@/pa_obj/pb_obj
ACTION=remove
DEVPATH=/pa_obj/pb_obj
SUBSYSTEM=p_kset
SEQNUM=1536
# echo '0' > /sys/pa_obj/pb_obj/child_attr
attr_store
buf[0] = 0x30
FLAG= 0add@/pa_obj/pb_obj
ACTION=add
DEVPATH=/pa_obj/pb_obj
SUBSYSTEM=p_kset
SEQNUM=1537
体会: netlink sys 这两种都可以用户空间和内核空间交换数据