当前位置:   article > 正文

linux文件系统

linux文件系统

  Linux的文件系统粗略的分为:
在这里插入图片描述

一、根文件系统

  根文件系统(rootfs)是内核启动时所 mount(挂载)的第一个文件系统,内核代码映像文件保存在根文件系中,而系统引导启动程序会在根文件系统挂载之后从中把一些基本的初始化脚本和服务等加载到内存中去运行。
  根文件系统的根目录/下有很多子目录:
在这里插入图片描述

二、虚拟文件系统

  虚拟文件系统VFS软件抽象层为用户屏蔽了底层文件系统的差异,向上层提供了统一地访问接口。如图:
在这里插入图片描述
  无论最下层的文件系统是什么,我们最上层的用户端尽管使用系统调用接口(open、write、read等)或glibc接口(fopen、fwrite、fread等)来操作就可访问文件系统里的文件,使得一切都是文件成为可能。

三、真文件系统

  真文件系统其实是实际存储设备的文件系统,挂载于EEPROM、 Nor FLASH、 NAND FLASH、 eMMC 等存储器中。

四、伪文件系统

  Linux内核提供了sysfs、procfs、devtmpfs等伪文件系统,伪文件系统存在于内存,不占用硬盘。以文件地形式向用户提供一些系统信息,用户读写这些文件就可以读取、修改系统的一些信息。

4.1、procfs

  procfs是 进程文件系统的缩写,包含一个伪文件系统(启动时动态生成的文件系统),用于通过内核访问进程信息。这个文件系统通常被挂载到 /proc 目录。
  由于 /proc 不是一个真正的文件系统,它也就不占用存储空间,只是占用有限的内存。/proc目录的内容如下:
在这里插入图片描述
  其中,这些以数字命名的文件夹就是与进程相关的部分,这些数字就是进程的PID号。我们可以访问系统信息,如读取CPU相关信息:
在这里插入图片描述
  查看内核支持的文件系统类型:
在这里插入图片描述

4.1.1、内核创建proc节点代码分析

  在kernel\fs\proc\cpuinfo.c文件中

// SPDX-License-Identifier: GPL-2.0
#include <linux/cpufreq.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>

__weak void arch_freq_prepare_all(void)
{
}

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

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

static int __init proc_cpuinfo_init(void)
{
	proc_create("cpuinfo", 0, NULL, &proc_cpuinfo_operations);
	return 0;
}
fs_initcall(proc_cpuinfo_init);
  • 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

  这就是创建/proc下cpuinfo这个节点的相关代码,有了cpuinfo节点,我们就可以通过访问这个节点来得到cpu的一些信息。其中proc_create这个函数来创造相关节点的,proc_create函数创建的与系统信息相关的节点存放于/proc目录下。

4.1.2、编写proc驱动

  proc驱动的编写不是基于交叉编译环境,而是基于ubuntu的本地编译环境编写

#include <linux/fs.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/module.h>
#include <linux/uaccess.h>

static char kernel_buf[1024];

#define MIN(a, b) (a < b ? a : b)

static int myproc_open(struct inode *node, struct file *file)
{
 printk("[%s %d][%s]\r\n", __FILE__, __LINE__, __FUNCTION__);
 return 0;
}

static ssize_t myproc_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
 int err;
 printk("[%s %d][%s]\r\n", __FILE__, __LINE__, __FUNCTION__);
 err = copy_to_user(buf, kernel_buf, MIN(1024, size));
 return MIN(1024, size);
}

static ssize_t myproc_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
 int err;
 printk("[%s %d][%s]\r\n", __FILE__, __LINE__, __FUNCTION__);
 err = copy_from_user(kernel_buf, buf, MIN(1024, size));
 return MIN(1024, size);
}

static int myproc_close(struct inode *node, struct file *file)
{
 printk("[%s %d][%s]\r\n", __FILE__, __LINE__, __FUNCTION__);
 return 0;
}

static const struct file_operations myproc_operations = 
{
 .owner  = THIS_MODULE,
 .open  = myproc_open,
 .read    = myproc_read,
 .write   = myproc_write,
 .release = myproc_close,
};

static int __init myproc_init(void)
{
 proc_create("myproc", 0, NULL, &myproc_operations);
 return 0;
}

static void __exit myproc_exit(void)
{
 remove_proc_entry("myproc", NULL);
}

module_init(myproc_init);
module_exit(myproc_exit);
MODULE_DESCRIPTION("proc test");
MODULE_LICENSE("GPL");
  • 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
4.1.3、编写makefile文件
KERNELDIR :=/usr/src/linux-headers-5.4.0-149-generic
CURRENT_PATH := $(shell pwd)
#禁用签名
CONFIG_MODULE_SIG=n

obj-m := proc.o

build: kernel_modules

kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules

clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
4.1.4、驱动加载与测试

  (1) 首先编译一下:

sudo make
  • 1

在这里插入图片描述
  **(2)**加载驱动

sudo insmod proc.ko
  • 1

在这里插入图片描述
  (3) 查看加载的模块
  使用指令:lsmod,或者:ls
在这里插入图片描述
  **(4)**给模块权限

sudo chmod 777 /proc/myproc
  • 1

  (5) 向模块写数据

echo "hello" > /proc/myproc
  • 1

在这里插入图片描述

  (6) 查看内核打印

dmesg
  • 1

在这里插入图片描述
  (7) 从模块读取数据

cat /proc/myproc
  • 1

在这里插入图片描述
  (8) 卸载模块

sudo rmmod proc
  • 1

在这里插入图片描述

4.2、devtmpfs

  devtmpfs 的功用是在 Linux 核心 启动早期建立一个初步的 /dev,令一般启动程序不用等待 udev(udev 是Linux kernel 2.6系列的设备管理器。它主要的功能是管理/dev目录底下的设备节点。),缩短 GNU/Linux 的开机时间。
  如果将一个设备连接到Linux系统时,通常需要一个设备驱动程序才能正常工作。此时通过设备文件或设备节点与设备驱动程序交互,这些是看起来像普通文件的特殊文件。由于这些设备文件就像普通文件一样,所以可以使用ls、cat等程序与它们交互。这些设备文件一般存放在/dev目录下,可以通过命令ls /dev查看/dev目录

4.3、sysfs

  sysfs是一个基于内存的文件系统,它的作用是将内核信息以文件的方式提供给用户程序使用。sysfs 文件系统被挂载在 /sys 挂载点上。
  Sysfs的目的是更好地管理系统上的设备,相比/dev目录无法做到这一点。Sysfs是一个虚拟文件系统,通常挂载在/sys目录下。它为我们提供了比在/dev目录中能够看到的更详细的信息。目录/sys和/dev在某些方面看起来非常相似,但它们确实有很大的不同。基本上,/dev目录很简单,它允许其他程序访问设备本身,而/sys文件系统用于查看信息和管理设备。
  /sys文件系统基本上包含了系统中所有设备的所有信息,比如制造商和型号、设备插入的位置、设备的状态、设备的层次结构等等。在这里看到的文件不是设备节点,因此实际上并不是在/sys目录下与设备交互,而是在管理设备。

五、网络文件系统

  NFS(Network File System) ,即网络文件系统, 能使使用者访问网络上别处的文件就像在使用自己的计算机一样。其工作原理是使用客户端/服务器架构 。
  服务器程序向其他计算机提供对文件系统的访问,其过程称为输出。NFS客户端程序对共享文件系统进行访问时,把它们从NFS服务器中“输送”出来。
  文件通常以块为单位进行传输。在我们嵌入式Linux中,NFS的主要应用如:把主机的上文件(比如目标板的可执行文件)共享给目标板,这样目标板就很方便地运行程序。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/263741
推荐阅读
相关标签
  

闽ICP备14008679号