这里文章的名字盗用《深入linux网络技术内幕》的名字,感觉它概念清晰,就顺手拿来用了. 那首先让我们想想用户空间与内核交互的接口都有哪些呢?做过内核或者驱动的人都会经常用到proc文件系统,两个字:强大! 还有ioctl ,另外一把神器。 还有netlink . 设备模型的热插拔机制、系统调用(c库)。 废话又说了这么多!下面切入正题.
procfs是内核用的文件系统,用于显示内核信息及交互内核参数(用户《===》内核).那么下面就分几点来分析:
1. 基本的proc文件系统的文件或目录的添加、删除
2. 特殊的proc文件的添加等
3. 内核中procfs文件系统的初始化
4. 常用的proc内核参数
对于第一点,也就是当时想去创建一个proc文件来和内核交互的时候,首先想到的,也是通用的.
这里我们环境是3.1.1 linux内核 ,在fs/proc/generic.c 里 看看这些接口的实现及其声明:
在proc目录下创建一个目录:
struct proc_dir_entry *proc_mkdir(const char *name,
struct proc_dir_entry *parent)
{
return proc_mkdir_mode(name, S_IRUGO | S_IXUGO, parent);
}
在proc下创建一个文件:
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
struct proc_dir_entry *parent)
{
struct proc_dir_entry *ent;
nlink_t nlink;
if (S_ISDIR(mode)) {
if ((mode & S_IALLUGO) == 0)
mode |= S_IRUGO | S_IXUGO;
nlink = 2;
} else {
if ((mode & S_IFMT) == 0)
mode |= S_IFREG;
if ((mode & S_IALLUGO) == 0)
mode |= S_IRUGO;
nlink = 1;
}
ent = __proc_create(&parent, name, mode, nlink);
if (ent) {
if (proc_register(parent, ent) < 0) {
kfree(ent);
ent = NULL;
}
}
return ent;
}
移除一个proc文件:
/*
* Remove a /proc entry and free it if it's not currently in use.
*/
void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
相关用法自己可以从linux源码里搜. 这里贴一个简单的例子:
struct proc_dir_entry *entry = create_proc_entry("my_proc", 0, NULL);
if(entry)
{
entry->read_proc = XXX_proc_read;
entry->write_proc = XXX_proc_write;
}
下面我们说第二点一些特殊的文件的相关操作:
<1> 在/proc/net/下创建我们需要的文件 ,这里procfs已经给出了接口:
extern struct proc_dir_entry *proc_net_fops_create(struct net *net,
const char *name, mode_t mode, const struct file_operations *fops);
extern void proc_net_remove(struct net *net, const char *name);
extern struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name,
struct proc_dir_entry *parent);
下面我们也看一个例子:
static int __net_init netlink_net_init(struct net *net)
{
#ifdef CONFIG_PROC_FS
if (!proc_net_fops_create(net, "netlink", 0, &netlink_seq_fops))
return -ENOMEM;
#endif
return 0;
}static const struct file_operations netlink_seq_fops = {
.owner = THIS_MODULE,
.open = netlink_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_net,
};
static const struct seq_operations netlink_seq_ops = {
.start = netlink_seq_start,
.next = netlink_seq_next,
.stop = netlink_seq_stop,
.show = netlink_seq_show,
};
static int netlink_seq_open(struct inode *inode, struct file *file)
{
return seq_open_net(inode, file, &netlink_seq_ops,
sizeof(struct nl_seq_iter));
}
<2>/proc/sys 它比较特殊. ---sysctl
这个目录下面都存放了一些内核变量. 它下面的文件和目录都是以ctl_table结构定义的.而ctl_table结构的注册和除名是通过在kernel/sysctl.c中定义的register_sysctl_table和unregister_sysctl_table来完成的.
关于它我们在后续文章中详细讲解.
对于第三点,具体的procfs的初始化工作,首先它是支持内核编译选项的,如何完成初始化工作我们自己看
fs/proc/ 下文件 ,首先看Makefile,对我们认识proc会有一个清晰的帮助. 这里我们可以参考fs/proc/root.c 等.
void __init proc_root_init(void)
{
struct vfsmount *mnt;
int err;
proc_init_inodecache();
err = register_filesystem(&proc_fs_type);
if (err)
return;
mnt = kern_mount_data(&proc_fs_type, &init_pid_ns);
if (IS_ERR(mnt)) {
unregister_filesystem(&proc_fs_type);
return;
}
init_pid_ns.proc_mnt = mnt;
proc_symlink("mounts", NULL, "self/mounts");
proc_net_init();
#ifdef CONFIG_SYSVIPC
proc_mkdir("sysvipc", NULL);
#endif
proc_mkdir("fs", NULL);
proc_mkdir("driver", NULL);
proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
/* just give it a mountpoint */
proc_mkdir("openprom", NULL);
#endif
proc_tty_init();
#ifdef CONFIG_PROC_DEVICETREE
proc_device_tree_init();
#endif
proc_mkdir("bus", NULL);
proc_sys_init();
}
proc文件系统也是基于VFS的,它仅仅存在于内存中.
当然我们知道proc如此的强大,一定有平时我们经常用到的一些参数,这里就简单的列几个:
查看cpu信息:
#cat /proc/cpuinfo
查看内存信息:
#cat /proc/meminfo
查看注册中断信息:
#cat /proc/interrupts
查看版本信息:
#cat /proc/version
查看内核导出符号表:
#cat /proc/kallsyms
查看所有内核打印信息:
#cat /proc/kmsg
查看设备或总线信息
#cat /proc/bus/*
查看网络信息
#cat /proc/net/**
#cat /proc/sys/net/**
当然还有其他许多这里就不一一列举了,proc在我们内核和驱动开发中是一把神兵! 推荐大家使用!
阅读(4911) | 评论(0) | 转发(3) |