在做内核驱动开发的时候,可以使用/proc下的文件,获取相应的信息,以便调试。

大多数/proc下的文件是只读的,但为了示例的完整性,都提供了写方法。

方法一:使用 create_proc_entry 创建 proc 文件(简单,但写操作有缓冲区溢出的危险);

方法二:使用 proc_createseq_file 创建 proc 文件(较方法三简洁);

方法三:使用 proc_create_dataseq_file 创建 proc 文件(较麻烦,但比较完整);

示例四:在 proc 文件中使用内核链表的一个示例(用的方法三)。


方法三、

proc_test04.c 源码

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
 
struct proc_head
{
	struct list_head lhead;
	int item_count;
	int str_count;
};
 
struct proc_item
{
	struct list_head litem;
	char *buf;
	int num;
};
 
struct proc_head *gp_head;
 
// linux/seq_file.h
// void * (*start) (struct seq_file *m, loff_t *pos);
// void (*stop) (struct seq_file *m, void *v);
// void * (*next) (struct seq_file *m, void *v, loff_t *pos);
// int (*show) (struct seq_file *m, void *v);
 
/**
* author:  aran
* fuction: seq_operations -> start
*/
static void *my_seq_start(struct seq_file *m, loff_t *pos)
{
	struct proc_item *entry;
 
	if (0 == *pos)
	{
		seq_printf(m, "List has %d items, total %d bytes\n", gp_head->item_count, gp_head->str_count);
	}
 
	// get first item
	++*pos;
	list_for_each_entry(entry, &gp_head->lhead, litem)
	{
		if (*pos == entry->num)
		{
			return entry;
		}
	}
	return NULL;
}
 
/**
* author:  aran
* fuction: seq_operations -> next
*/
static void *my_seq_next(struct seq_file *m, void *v, loff_t *pos)
{
	struct proc_item *entry;
 
	// get next item
	++*pos;
	list_for_each_entry(entry, &gp_head->lhead, litem)
	{
		if (*pos == entry->num)
		{
			return entry;
		}
	}
	return NULL;
}
 
/**
* author:  aran
* fuction: seq_operations -> stop
*/
static void my_seq_stop(struct seq_file *m, void *v)
{
	// clean sth.
	// nothing to do
}
 
/**
* author:  aran
* fuction: seq_operations -> show
*/
static int my_seq_show(struct seq_file *m, void *v)
{
	struct proc_item *tmp = v;
	seq_printf(m, "%s", tmp->buf);
 
	return 0;
}
 
// global var
static struct seq_operations my_seq_fops = 
{
	.start	= my_seq_start,
	.next	= my_seq_next,
	.stop	= my_seq_stop,
	.show	= my_seq_show,
};
 
// file_operations
// int (*open) (struct inode *, struct file *)
// ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *)
 
/**
* author:  aran
* fuction: file_operations -> open
*/
static int proc_seq_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &my_seq_fops);
}
 
/**
* author:  aran
* fuction: file_operations -> write
*/
static ssize_t proc_seq_write(struct file *file, const char __user *buffer, size_t count, loff_t *f_pos)
{
	struct proc_item *tmp;
	int ret;
 
	// allocate proc_item
	tmp = (struct proc_item *)kzalloc(sizeof(*tmp), GFP_KERNEL);
	if (NULL == tmp)
	{
		ret = -ENOMEM;
		goto err_kzalloc1;
	}
	INIT_LIST_HEAD(&tmp->litem);
 
	// allocate str buf
	tmp->buf = (char *)kzalloc(count, GFP_KERNEL);
	if (NULL == tmp->buf)
	{
		ret = -ENOMEM;
		goto err_kzalloc2;
	}
 
	if (0 != copy_from_user(tmp->buf, buffer, count))
	{
		ret = -1;
		goto err_copy;
	}
 
	list_add(&tmp->litem, &gp_head->lhead);
	gp_head->item_count++;
	gp_head->str_count += count;
	tmp->num = gp_head->item_count; 
 
	return count;
 
err_copy:
	kfree(tmp->buf);
err_kzalloc2:
	kfree(tmp);
err_kzalloc1:
	return ret;
}
 
// global var
static struct file_operations proc_seq_fops = 
{
	.owner		= THIS_MODULE,
	.open		= proc_seq_open,
	.read		= seq_read,
	.write		= proc_seq_write,
	.llseek		= seq_lseek,
	.release	= seq_release,
};
 
static int __init my_init(void)
{
	struct proc_dir_entry *file;
	int ret;
 
	// allocate & init proc_head
	gp_head = (struct proc_head *)kzalloc(sizeof(*gp_head), GFP_KERNEL);
	if (NULL == gp_head)
	{
		ret = -ENOMEM;
		goto err_kzalloc;
	}
	gp_head->item_count = 0;
	gp_head->str_count = 0;
	INIT_LIST_HEAD(&gp_head->lhead);
 
	// create "/proc/proc_seq" file
	file = proc_create_data(
		"proc_seq",	// name
		0666,		// mode
		NULL,		// parent dir_entry
		&proc_seq_fops,	// file_operations
		NULL		// data
		);
	if (NULL == file)
	{
		printk("Count not create /proc/proc_seq file!\n");
		ret = -1;
		goto err_proc_create_data;
	}
 
	return 0;
 
err_proc_create_data:
	kfree(gp_head);
err_kzalloc:
	return ret;
}
 
static void __exit my_exit(void)
{
	struct proc_item *tmp1, *tmp2;
 
	remove_proc_entry("proc_seq", NULL);
	list_for_each_entry_safe(tmp1, tmp2, &gp_head->lhead,litem)
	{
		list_del(&tmp1->litem);
		kfree(tmp1->buf);
		kfree(tmp1);
	}
	kfree(gp_head);
}
 
module_init(my_init);
module_exit(my_exit);
 
MODULE_AUTHOR("aran");
MODULE_LICENSE("GPL");

Makefile文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
obj-m	:= proc_test04.o
KERNEL	:= /lib/modules/`uname -r`/build #for mint/ubuntu
#KERNEL	:= /lib/modules/`uname -r`/source #for redhat
 
all:
	make -C $(KERNEL) M=`pwd` modules
 
install:
	make -C $(KERNEL) M=`pwd` modules_install
	depmod -A
 
clean:
	make -C $(KERNEL) M=`pwd` clean

测试结果

测试结果