您的位置:首页 > 运维架构 > Linux

linux设备驱动学习笔记--内核调试方法之proc(补充seq_file)

2015-02-01 23:11 459 查看
上一节中的proc实现对于开关文件,控制文件,以及显示很少信息的文件来说还是比较简单的,但是对于需要输出大量信息像meminfo,或者结构化的信息像cpuinfo等时就会显得很笨拙,并且代码也很不好理解与维护。内核为了简化这种proc文件的实现提供了另外一种方案----seq_file接口。

set_file 接口假定你在创建一个虚拟文件, 它涉及一系列的必须返回给用户空间的项. 为使用 seq_file, 你必须创建一个简单的 "iterator" 对象, 它能在序列里建立一个位置(start), 向前进(next), 并且输出序列里的一个项(show). 它可能听起来复杂,但实际上过程非常简单.

seq_file接口即可以实现以前的非结构化的信息显示,也可以实现结构化的信息显示,并且两种实现的代码都比较简单清晰。使用seq_file接口需要包含头文件<linux/seq_file.h>。

seq_file的使用比较规范,与其他文件操作步骤比较一致,所以看起来也比较容易,我们可以通过分析内核中对meminfo和cpuinfo来学习非结构化与结构化信息显示的实现步骤。

1,结构化信息显示方式

第一步:在模块初始化时调用proc_create来创建相应proc文件

static int __init proc_cpuinfo_init(void)
{
proc_create("cpuinfo", 0, NULL, &proc_cpuinfo_operations);
return 0;
}


第二步:在模块卸载时调用remove_proc_entry函数删除相应的proc文件,当然因为cpuinfo的实现在内核代码中,不涉及到卸载,所以cpuinfo没有删除相应proc文件的操作,但是我们自己编写的内核模块涉及此场景,所以需要实现此步骤。

第三步:定义file_operations结构体(第一步中创建时会使用)

static const struct file_operations proc_cpuinfo_operations = {
.open		= cpuinfo_open,
.read		= seq_read,
.llseek		= seq_lseek,
.release	= seq_release,
};


第四步,实现file_operations的open函数,在open函数中建议proc文件与seq_file机制的四个迭代器的联系。而read、llseek、release等都是seq_file实现好的框架,不需要另外实现。

extern const struct seq_operations cpuinfo_op;
static int cpuinfo_open(struct inode *inode, struct file *file)
{
return seq_open(file, &cpuinfo_op);
}


第五步,定义seq_operations结构体

const struct seq_operations cpuinfo_op = {
.start	= c_start,
.next	= c_next,
.stop	= c_stop,
.show	= show_cpuinfo,
};


第六步,实现迭代器(start/next/stop/show),按自己需要来实现,这里只是cpuinfo的实现

start迭代器:

static void *c_start(struct seq_file *m, loff_t *pos)
{
*pos = cpumask_next(*pos - 1, cpu_online_mask);
if ((*pos) < nr_cpu_ids)
return &cpu_data(*pos);
return NULL;
}


next迭代器:
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
{
(*pos)++;
return c_start(m, pos);
}


stop迭代器,一般实现为空

static void c_stop(struct seq_file *m, void *v)
{
}


show迭代器,最主要的信息显示

static int show_cpuinfo(struct seq_file *m, void *v)
{
struct cpuinfo_x86 *c = v;
unsigned int cpu;
int i;

cpu = c->cpu_index;
seq_printf(m, "processor\t: %u\n"
"vendor_id\t: %s\n"
"cpu family\t: %d\n"
"model\t\t: %u\n"
"model name\t: %s\n",
cpu,
c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
c->x86,
c->x86_model,
c->x86_model_id[0] ? c->x86_model_id : "unknown");

if (c->x86_mask || c->cpuid_level >= 0)
seq_printf(m, "stepping\t: %d\n", c->x86_mask);
else
seq_printf(m, "stepping\t: unknown\n");
if (c->microcode)
seq_printf(m, "microcode\t: 0x%x\n", c->microcode);

if (cpu_has(c, X86_FEATURE_TSC)) {
unsigned int freq = cpufreq_quick_get(cpu);

if (!freq)
freq = cpu_khz;
seq_printf(m, "cpu MHz\t\t: %u.%03u\n",
freq / 1000, (freq % 1000));
}

/* Cache size */
if (c->x86_cache_size >= 0)
seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);

show_cpuinfo_core(m, c, cpu);
show_cpuinfo_misc(m, c);

seq_printf(m, "flags\t\t:");
for (i = 0; i < 32*NCAPINTS; i++)
if (cpu_has(c, i) && x86_cap_flags[i] != NULL)
seq_printf(m, " %s", x86_cap_flags[i]);

seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
c->loops_per_jiffy/(500000/HZ),
(c->loops_per_jiffy/(5000/HZ)) % 100);

#ifdef CONFIG_X86_64
if (c->x86_tlbsize > 0)
seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize);
#endif
seq_printf(m, "clflush size\t: %u\n", c->x86_clflush_size);
seq_printf(m, "cache_alignment\t: %d\n", c->x86_cache_alignment);
seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n",
c->x86_phys_bits, c->x86_virt_bits);

seq_printf(m, "power management:");
for (i = 0; i < 32; i++) {
if (c->x86_power & (1 << i)) {
if (i < ARRAY_SIZE(x86_power_flags) &&
x86_power_flags[i])
seq_printf(m, "%s%s",
x86_power_flags[i][0] ? " " : "",
x86_power_flags[i]);
else
seq_printf(m, " [%d]", i);
}
}

seq_printf(m, "\n\n");

return 0;
}


2,非结构化信息显示方式

第一步:在模块初始化时调用proc_create来创建相应proc文件

static int __init proc_meminfo_init(void)
{
proc_create("meminfo", 0, NULL, &meminfo_proc_fops);
return 0;
}


第二步:在模块卸载时调用remove_proc_entry函数删除相应的proc文件,当然因为meminfo的实现在内核代码中,不涉及到卸载,所以meminfo没有删除相应proc文件的操作,但是我们自己编写的内核模块涉及此场景,所以需要实现此步骤。

第三步:定义file_operations结构体(第一步中创建时会使用)

static const struct file_operations meminfo_proc_fops = {
.open		= meminfo_proc_open,
.read		= seq_read,
.llseek		= seq_lseek,
.release	= single_release,
};


第四步,实现file_operations的open函数,因为meminfo是非结构化信息显示,所以我们不需要实现start/next/stop等迭代器,只需要实现show来显示信息即可,所以不需要像cpuinfo一样需要定义一个seq_operations结构体并且调用seq_open来建立proc文件与seq_file迭代器之间的联系。seq_file接口对于非结构化的信息显示情况提供了一个single_open接口,所以在open中调用single_open。

static int meminfo_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, meminfo_proc_show, NULL);
}


第五步,只需要实现show迭代器meminfo_proc_show即可

static int meminfo_proc_show(struct seq_file *m, void *v)
{
struct sysinfo i;
unsigned long committed;
unsigned long allowed;
struct vmalloc_info vmi;
long cached;
unsigned long pages[NR_LRU_LISTS];
int lru;

/*
* display in kilobytes.
*/
#define K(x) ((x) << (PAGE_SHIFT - 10))
si_meminfo(&i);
si_swapinfo(&i);
committed = percpu_counter_read_positive(&vm_committed_as);
allowed = ((totalram_pages - hugetlb_total_pages())
* sysctl_overcommit_ratio / 100) + total_swap_pages;

cached = global_page_state(NR_FILE_PAGES) -
total_swapcache_pages - i.bufferram;
if (cached < 0)
cached = 0;

get_vmalloc_info(&vmi);

for (lru = LRU_BASE; lru < NR_LRU_LISTS; lru++)
pages[lru] = global_page_state(NR_LRU_BASE + lru);

/*
* Tagged format, for easy grepping and expansion.
*/
seq_printf(m,
"MemTotal:       %8lu kB\n"
"MemFree:        %8lu kB\n"
"Buffers:        %8lu kB\n"
"Cached:         %8lu kB\n"
"SwapCached:     %8lu kB\n"
"Active:         %8lu kB\n"
"Inactive:       %8lu kB\n"
"Active(anon):   %8lu kB\n"
"Inactive(anon): %8lu kB\n"
"Active(file):   %8lu kB\n"
"Inactive(file): %8lu kB\n"
"Unevictable:    %8lu kB\n"
"Mlocked:        %8lu kB\n"
#ifdef CONFIG_HIGHMEM
"HighTotal:      %8lu kB\n"
"HighFree:       %8lu kB\n"
"LowTotal:       %8lu kB\n"
"LowFree:        %8lu kB\n"
#endif
#ifndef CONFIG_MMU
"MmapCopy:       %8lu kB\n"
#endif
"SwapTotal:      %8lu kB\n"
"SwapFree:       %8lu kB\n"
"Dirty:          %8lu kB\n"
"Writeback:      %8lu kB\n"
"AnonPages:      %8lu kB\n"
"Mapped:         %8lu kB\n"
"Shmem:          %8lu kB\n"
"Slab:           %8lu kB\n"
"SReclaimable:   %8lu kB\n"
"SUnreclaim:     %8lu kB\n"
"KernelStack:    %8lu kB\n"
"PageTables:     %8lu kB\n"
#ifdef CONFIG_QUICKLIST
"Quicklists:     %8lu kB\n"
#endif
"NFS_Unstable:   %8lu kB\n"
"Bounce:         %8lu kB\n"
"WritebackTmp:   %8lu kB\n"
"CommitLimit:    %8lu kB\n"
"Committed_AS:   %8lu kB\n"
"VmallocTotal:   %8lu kB\n"
"VmallocUsed:    %8lu kB\n"
"VmallocChunk:   %8lu kB\n"
#ifdef CONFIG_MEMORY_FAILURE
"HardwareCorrupted: %5lu kB\n"
#endif
,
K(i.totalram),
K(i.freeram),
K(i.bufferram),
K(cached),
K(total_swapcache_pages),
K(pages[LRU_ACTIVE_ANON]   + pages[LRU_ACTIVE_FILE]),
K(pages[LRU_INACTIVE_ANON] + pages[LRU_INACTIVE_FILE]),
K(pages[LRU_ACTIVE_ANON]),
K(pages[LRU_INACTIVE_ANON]),
K(pages[LRU_ACTIVE_FILE]),
K(pages[LRU_INACTIVE_FILE]),
K(pages[LRU_UNEVICTABLE]),
K(global_page_state(NR_MLOCK)),
#ifdef CONFIG_HIGHMEM
K(i.totalhigh),
K(i.freehigh),
K(i.totalram-i.totalhigh),
K(i.freeram-i.freehigh),
#endif
#ifndef CONFIG_MMU
K((unsigned long) atomic_long_read(&mmap_pages_allocated)),
#endif
K(i.totalswap),
K(i.freeswap),
K(global_page_state(NR_FILE_DIRTY)),
K(global_page_state(NR_WRITEBACK)),
K(global_page_state(NR_ANON_PAGES)),
K(global_page_state(NR_FILE_MAPPED)),
K(global_page_state(NR_SHMEM)),
K(global_page_state(NR_SLAB_RECLAIMABLE) +
global_page_state(NR_SLAB_UNRECLAIMABLE)),
K(global_page_state(NR_SLAB_RECLAIMABLE)),
K(global_page_state(NR_SLAB_UNRECLAIMABLE)),
global_page_state(NR_KERNEL_STACK) * THREAD_SIZE / 1024,
K(global_page_state(NR_PAGETABLE)),
#ifdef CONFIG_QUICKLIST
K(quicklist_total_size()),
#endif
K(global_page_state(NR_UNSTABLE_NFS)),
K(global_page_state(NR_BOUNCE)),
K(global_page_state(NR_WRITEBACK_TEMP)),
K(allowed),
K(committed),
(unsigned long)VMALLOC_TOTAL >> 10,
vmi.used >> 10,
vmi.largest_chunk >> 10
#ifdef CONFIG_MEMORY_FAILURE
,atomic_long_read(&mce_bad_pages) << (PAGE_SHIFT - 10)
#endif
);

hugetlb_report_meminfo(m);

arch_report_meminfo(m);

return 0;
#undef K
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐