编写内核模块,获取磁盘的disk_stats信息
我正在写一个内核模块,基于linux 2.6.32。这个模块的功能是获取所有磁盘的disk_stats,最后展示的结果与文件/sys/block/sda/stat的内容相似。
想问一下,对于block device,有没有类似于for_each_netdev的宏/函数,因为一台机器可能有多个磁盘,我需要遍历这些磁盘。或者,有没有什么方法可以根据块设备的名字(比如sda)获取到相应的数据结构。一块磁盘的disk_stats,存放在struct hd_struct,如何获取到这个hd_struct?
我看了linux2.6.32/block/genhd.c,/sys/block/sda/stat的内容是由genhd.c的diskstats_show函数产生的,不过这个函数被调用的时候,第二个参数应该是什么?如何获取到这个参数?
对于block device,linux 2.4有一个全局变量gendisk_head,但是linux2.6好像找不到了。
求大牛帮忙,感激不尽。 回复 1# motorn
你要的东西就在genhd.c这个文件里。/*
* aggregate disk stat collector.Uses the same stats that the sysfs
* entries do, above, but makes them available through one seq_file.
* Watching a few disks may be efficient through sysfs, but watching
* all of them will be more efficient through this interface.
*
* The output looks suspiciously like /proc/partitions with a bunch of
* extra fields.
*/
/* iterator */
static void *diskstats_start(struct seq_file *part, loff_t *pos)
{
loff_t k = *pos;
struct list_head *p;
mutex_lock(&block_subsys_lock);
list_for_each(p, &block_subsys.list)
if (!k--)
return list_entry(p, struct gendisk, kobj.entry);
return NULL;
}
static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos)
{
struct list_head *p = ((struct gendisk *)v)->kobj.entry.next;
++*pos;
return p==&block_subsys.list ? NULL :
list_entry(p, struct gendisk, kobj.entry);
}
static void diskstats_stop(struct seq_file *part, void *v)
{
mutex_unlock(&block_subsys_lock);
}你太不认真的。你怎么只看diskstats_show,不看和他一套的函数呢。
如果对seq_operations不熟,自己去baidu.com!! 本帖最后由 motorn 于 2014-05-19 23:11 编辑
回复 2# Tinnal
你好,你提到的diskstats_{start, next, stop},在linux 2.6.25及以前的版本中存在,之后就不存在了,看这里。不过我在linux 2.6.32中找到了类似的一组函数:disk_seqf_{start, next, stop},看这里,这组函数从linux 2.6.31开始出现。
但是有一个问题:对于linux 2.6.25,diskstats_start的实现中用到了一个变量block_subsys,它在drivers/block/genhd.c中定义的,在这里,可以看到,它是static的,即文件内可见。所以,你写个内核模块装载到内核之后,你是看不到这个变量的。所以也就没法把这几个函数“依葫芦画瓢”地再实现一遍。(为什么要再实现一遍?因为genhd.c里这几个函数是static的,而你要在你的模块里获得类似的功能)
同样的,对于linux 2.6.32,disk_seqf_start的实现中用到了一个变量block_class,它也是在block/genhd.c中定义的,看这里,可以看到,它虽不是static的,但是它在定义之后并没有EXPORT_SYMBOL。linux内核在2.4之后,凡是没有EXPORT_SYMBOL的全局变量,不管它是不是static的,它都只是文件可见,不是真正的全局(即整个模块可见)。所以,我们遇到了同样的问题。 回复 2# Tinnal #ifdef CONFIG_PROC_FS
/* iterator */
static void *disk_seqf_start(struct seq_file *seqf, loff_t *pos)
{
loff_t skip = *pos;
struct class_dev_iter *iter;
struct device *dev;
iter = kmalloc(sizeof(*iter), GFP_KERNEL);
if (!iter)
return ERR_PTR(-ENOMEM);
seqf->private = iter;
class_dev_iter_init(iter, &block_class, NULL, &disk_type);
do {
dev = class_dev_iter_next(iter);
if (!dev)
return NULL;
} while (skip--);
return dev_to_disk(dev);
}
static void *disk_seqf_next(struct seq_file *seqf, void *v, loff_t *pos)
{
struct device *dev;
(*pos)++;
dev = class_dev_iter_next(seqf->private);
if (dev)
return dev_to_disk(dev);
return NULL;
}
static void disk_seqf_stop(struct seq_file *seqf, void *v)
{
struct class_dev_iter *iter = seqf->private;
/* stop is called even after start failed :-( */
if (iter) {
class_dev_iter_exit(iter);
kfree(iter);
}
}
回复 4# motorn
这个函数是你想要的。void class_dev_iter_init(struct class_dev_iter *iter, struct class *class,
struct device *start, const struct device_type *type)
{
struct klist_node *start_knode = NULL;
if (start)
start_knode = &start->knode_class;
klist_iter_init_node(&class->p->class_devices, &iter->ki, start_knode);
iter->type = type;
}
EXPORT_SYMBOL_GPL(class_dev_iter_init);这也是你要的。void class_dev_iter_init(struct class_dev_iter *iter, struct class *class,
struct device *start, const struct device_type *type)
{
struct klist_node *start_knode = NULL;
if (start)
start_knode = &start->knode_class;
klist_iter_init_node(&class->p->class_devices, &iter->ki, start_knode);
iter->type = type;
}
EXPORT_SYMBOL_GPL(class_dev_iter_init);至于其他,你自己写呀,大哥。struct class block_class = {
.name = "block",
};
这个这么简单的的定义你也非得要用别人的? 这些函数都只是让你参考,也不是让你直接去用,而且也没必要去抄。这几个函数代码量又不大,你抄来干嘛。
你要真纠结,就把他们EXPORT_SYMBOL_GPL。{:2_174:}
页:
[1]