linux内核源码分析之proc文件系统(二)

目录

1、功能介绍

2、源码实现框架

3、源码


内核提供proc文件系统注册的源码

1、功能介绍

在proc注册的目录 procfs_example,在此目录下建立了bar,foo,jiffies文件以及一个软连接jiffies_too,目录结构如下:

(base) root@ubuntu:/proc/procfs_example# ls -l
total 0
-r--r--r-- 1 root root 0 Mar 25 06:50 bar
-r--r--r-- 1 root root 0 Mar 25 06:50 foo
-r--r--r-- 1 root root 0 Mar 25 06:50 jiffies
lrwxrwxrwx 1 root root 7 Mar 25 06:50 jiffies_too -> jiffies

查看文件内容信息

(base) root@ubuntu:/proc/procfs_example# cat bar 
bar='bar'
(base) root@ubuntu:/proc/procfs_example# cat foo 
foo='foo'
(base) root@ubuntu:/proc/procfs_example# cat jiffies
jiffies=4300908124
(base) root@ubuntu:/proc/procfs_example# cat jiffies
jiffies=4300908884
(base) root@ubuntu:/proc/procfs_example# cat jiffies_too
jiffies=4300917124

修改bar,foo内容并查看

(base) root@ubuntu:/proc/procfs_example# echo "good" > bar
(base) root@ubuntu:/proc/procfs_example# cat bar 
bar='good'

(base) root@ubuntu:/proc/procfs_example# echo "good" > foo
(base) root@ubuntu:/proc/procfs_example# cat foo 
foo='good'

软连接修改出现错误,源码中有给出原因(没有实现对应的写函数)

(base) root@ubuntu:/proc/procfs_example# echo "good" > jiffies_too
-bash: echo: write error: Input/output error

(base) root@ubuntu:/proc/procfs_example# echo "good" > jiffies
-bash: echo: write error: Input/output error

2、源码实现框架

源码实现框架。以模块的方式实现,与驱动程序模式一样

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <asm/switch_to.h>
#include <generated/autoconf.h>
#include <linux/uaccess.h>

#define MODULE_VERS "1.0"
#define MODULE_NAME "procfs_example"
#define FOOBAR_LEN 8

struct fb_data_t{
	char name[FOOBAR_LEN+1];
	char value[FOOBAR_LEN+1];
};

static ssize_t read_jiffies_proc(struct file *filp,char __user *buf,size_t count,loff_t *offp ){

	copy_to_user(buf, tempstring, count);

	return count;
}
//只有读
static const struct file_operations jiffies_proc_fops={
	.read=read_jiffies_proc
};


static ssize_t read_foo_proc(struct file *filp,char __user *buf,size_t count,loff_t *offp ) {
	
	//使用cat 查看文件 调用copy_to_user
	//tempstr为数据内容
	copy_to_user(buf, tempstr, count);
	
	return count;
}
static ssize_t write_foo_proc(struct file *filp,const char __user *buf,size_t count,loff_t *offp ){
	//命令行使用echo写入数据 调用copy_from_user
	copy_from_user(foo_data.value, buf, len)
}

//读写都有
static const struct file_operations foo_proc_fops={
	.read=read_foo_proc,
	.write=write_foo_proc
};
	

static int __init init_procfs_example(void){
	int rv=0;

	//创建目录
	example_dir=proc_mkdir("procfs_example", NULL);

	//在procfs_example目录下创建jiffies,并注册文件操作jiffies_proc_fops
	jiffies_file=proc_create("jiffies", 0444, example_dir, &jiffies_proc_fops);

	//在procfs_example目录下创建foo,并注册文件操作foo_proc_fops
	foo_file=proc_create("foo", 0, example_dir, &foo_proc_fops);
	
	//在procfs_example目录下创建软连接jiffies_too,并连接到jiffies文件
	symlink=proc_symlink("jiffies_too", example_dir, "jiffies");

	return 0;
}

static void __exit cleanup_procfs_example(void){
	remove_proc_entry("jiffies_too", example_dir);
	remove_proc_entry("bar", example_dir);
	remove_proc_entry("jiffies", example_dir);
	remove_proc_entry("procfs_example", NULL);
}
module_init(init_procfs_example);
module_exit(cleanup_procfs_example);
MODULE_AUTHOR("wyong");
MODULE_DESCRIPTION("proc filesystem demo");

proc提供的函数:

  • proc_mkdir 创建目录,并挂载到/proc上
  • proc_create 创建文件,访问权限可以显示确定
  • proc_symlink 生成一个符号链接。
  • 从proc目录中删除一个动态生成的数据项

3、源码

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <asm/switch_to.h>
#include <generated/autoconf.h>
#include <linux/uaccess.h>

#define MODULE_VERS "1.0"
#define MODULE_NAME "procfs_example"
#define FOOBAR_LEN 8

struct fb_data_t{
	char name[FOOBAR_LEN+1];
	char value[FOOBAR_LEN+1];
};

static struct proc_dir_entry *example_dir, *foo_file, *bar_file, *jiffies_file, *symlink;
struct fb_data_t foo_data, bar_data;
int foo_len,foo_temp,bar_len,bar_temp;
int jiff_temp=-1;
char tempstr[FOOBAR_LEN*2+5];


static ssize_t read_jiffies_proc(struct file *filp,char __user *buf,size_t count,loff_t *offp ){
	printk(KERN_INFO"count=%d  jiff_temp=%d\n", count, jiff_temp);
	char tempstring[100]="";
	if (jiff_temp!=0)
		jiff_temp=sprintf(tempstring, "jiffies=%ld\n", jiffies);	
	if (count>jiff_temp)
		count=jiff_temp;
	jiff_temp=jiff_temp-count;

	printk(KERN_INFO"count=%d  jiff_temp=%d\n", count, jiff_temp);
	copy_to_user(buf, tempstring, count);
	if (count==0)
		jiff_temp=-1;	
	return count;
}
static const struct file_operations jiffies_proc_fops={
	.read=read_jiffies_proc
};


static ssize_t read_foo_proc(struct file *filp,char __user *buf,size_t count,loff_t *offp ) {
	printk(KERN_INFO"count=%d\n", count);
	
	if (count>foo_temp)
		count=foo_temp;
	foo_temp=foo_temp-count;

	strcpy(tempstr, foo_data.name);
	strcat(tempstr, "='");
	strcat(tempstr, foo_data.value);
	strcat(tempstr, "'\n");

	printk(KERN_INFO"count=%d  length(tempstr)=%d\n", count, strlen(tempstr));
	
	copy_to_user(buf, tempstr, count);
	if (count==0)
		foo_temp=foo_len+4;
	return count;
}
static ssize_t write_foo_proc(struct file *filp,const char __user *buf,size_t count,loff_t *offp ){
	int len;
	if (count>FOOBAR_LEN)
		len=FOOBAR_LEN;
	else
		len=count;

	if (copy_from_user(foo_data.value, buf, len))
		return -EFAULT;
	foo_data.value[len-1]='\0';	
	
	foo_len=strlen(foo_data.name)+strlen(foo_data.value);
	foo_temp=foo_len+4;
	return len;
}
static const struct file_operations foo_proc_fops={
	.read=read_foo_proc,
	.write=write_foo_proc
};

static ssize_t read_bar_proc(struct file *filp,char __user *buf,size_t count,loff_t *offp ) {	
	printk(KERN_INFO"count=%d\n", count);
	if (count>bar_temp)
		count=bar_temp;
	bar_temp=bar_temp-count;

	strcpy(tempstr, bar_data.name);
	strcat(tempstr, "='");
	strcat(tempstr, bar_data.value);
	strcat(tempstr, "'\n");
	printk(KERN_INFO"count=%d  length(tempstr)=%d\n", count, strlen(tempstr));
	copy_to_user(buf, tempstr, count);
	if (count==0)
		bar_temp=bar_len+4;
	return count;
}
static ssize_t write_bar_proc(struct file *filp,const char __user *buf,size_t count,loff_t *offp ){
	int len;
	if (count>FOOBAR_LEN)
		len=FOOBAR_LEN;
	else
		len=count;
	if (copy_from_user(bar_data.value, buf, len))
		return -EFAULT;
	bar_data.value[len-1]='\0';
	bar_len=strlen(bar_data.name)+strlen(bar_data.value);
	bar_temp=bar_len+4;
	return len;
}
static const struct file_operations bar_proc_fops={
	.read=read_bar_proc,
	.write=write_bar_proc
};


static int __init init_procfs_example(void){
	int rv=0;
	
	example_dir=proc_mkdir(MODULE_NAME, NULL);
	if (example_dir==NULL){
		rv=-ENOMEM;
		goto out;
	}

	jiffies_file=proc_create("jiffies", 0444, example_dir, &jiffies_proc_fops);
	if (jiffies_file==NULL){
		rv=-ENOMEM;
		goto no_jiffies;
	}
	
	strcpy(foo_data.name, "foo");
	strcpy(foo_data.value, "foo");
	foo_len=strlen(foo_data.name)+strlen(foo_data.value);
	foo_temp=foo_len+4;		
	foo_file=proc_create("foo", 0, example_dir, &foo_proc_fops);
	if (foo_file==NULL){
		rv=-ENOMEM;
		goto no_foo;
	}

	strcpy(bar_data.name, "bar");
	strcpy(bar_data.value, "bar");
	bar_len=strlen(bar_data.name)+strlen(bar_data.value);
	bar_temp=bar_len+4;
	bar_file=proc_create("bar", 0, example_dir, &bar_proc_fops);
	if (bar_file==NULL){
		rv=-ENOMEM;
		goto no_bar;
	}
	
	symlink=proc_symlink("jiffies_too", example_dir, "jiffies");
	if (symlink==NULL){
		rv=-ENOMEM;
		goto no_symlink;
	}

	printk(KERN_INFO"%s%s initialised\n", MODULE_NAME, MODULE_VERS);
	return 0;

no_symlink:
	remove_proc_entry("bar", example_dir);
no_bar:
	remove_proc_entry("foo", example_dir);
no_foo:
	remove_proc_entry("jiffies", example_dir);
no_jiffies:
	remove_proc_entry(MODULE_NAME, NULL);
out:
	return rv;
}

static void __exit cleanup_procfs_example(void){
	remove_proc_entry("jiffies_too", example_dir);
	remove_proc_entry("bar", example_dir);
	remove_proc_entry("foo", example_dir);
	remove_proc_entry("jiffies", example_dir);
	remove_proc_entry(MODULE_NAME, NULL);
	printk(KERN_INFO"%s%s removed\n", MODULE_NAME, MODULE_VERS);
}
module_init(init_procfs_example);
module_exit(cleanup_procfs_example);
MODULE_AUTHOR("Zhang Le");
MODULE_DESCRIPTION("proc filesystem example");

在下一篇文章中介绍具体的实现


参考:
《深入理解linux内核》
《Linux内核深度解析》

 内核源码

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Linux文件系统是指Linux内核提供的一种特殊的文件系统,其中最常见的是/proc目录下的procfs文件系统。它是一个在内存中存在的文件系统,不占用硬盘空间。通过procfs文件系统,用户可以查看系统硬件和当前正在运行的进程的信息,甚至可以通过更改其中某些文件来改变内核的运行状态。此外,Linux内核还提供了其他伪文件系统,如sysfs和devfs,它们也以文件的形式向用户提供了访问系统内核数据的接口。通过这些数据接口,用户和应用程序可以获取系统的信息,并且内核也允许用户修改一些参数。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Linux详解(内核和伪文件系统)](https://blog.csdn.net/weixin_44983653/article/details/94732559)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Linux文件系统](https://blog.csdn.net/PythonLife/article/details/114768584)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为了维护世界和平_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值