实验七:文件系统
任务1:为 Ext4 文件系统添加扩展属性
文件扩展属性的使用
1、环境准备
为了使用扩展属性,需要安装 libattr:
2、如何查看当前文件系统类型
df -Th
3、检查当前文件系统是否支持文件扩展属性
(1)用 fdisk -l 查看硬盘及分区信息
(2)用 tune2fs -l 显示设备的详细信息
通过检查/dev/vda2文件系统参数中的默认挂载选项“Default mount options”是否有对应内容;来确定分区设备的文件系统是否支持扩展属性——上图所示说明,该文件系统支持扩展用户属性user_xattr、与ACL权限
4、文件扩展属性的设置
(1)setfattr
设置文件系统对象的扩展属性(无文件系统限制)
语法:setfattr [-h] -n name [-v value] pathname...
setfattr [-h] -x name pathname...
setfattr [-h] --restore=file
(2)getfattr
获取文件系统对象的扩展属性
-n name:显示指定名称的属性。
-d:显示所有属性的值。
-e en:在提取属性之后进行编码,en的值为text、hex和base64。
en= "text"时,编码为文本的字符串的值用双引号(“)引起来;
en= "hex"时,编码为十六进制的字符串以0x为前缀;
en= "base64"时,编码为base64的字符串以0s为前缀。
任务描述
-
使用setfattr设置文件系统的用户扩展属性,并设置文本、八进制数、十六进制数与base64编码这四种属性值。
-
使用getfattr获取文件系统的用户扩展属性,并在获取属性之后进行text、hex和base64这三种编码设置。
(1)对于不含转义字符 \ 的纯文本属性值
有无双引号限定效果一样
(2)对于包含转义字符 \ 的文本属性值
无双引号则不对转义符 \ 进行转义;有双引号则对其进行转义。
例如:设置八进制数时,设置属性值为 \012 时,最终识别为文本012;设置属性值为“\012”时,最终以八进制数的base64编码存储。
(3)设置属性值为十六进制数时
所设置的数的位数必须为偶数,即0x 或 0X后的数字必须为偶数位,否则出错。 若设置成功,最终以十六进制数的base64编码存储。
(4)设置属性值为base64编码时
所设置的编码必须符合base64编码,即0s后的编码字符串必须符合base64编码,否则出错。 若设置成功,最终以base64编码对应的文本信息存储。
tips:可在base64.us/ 中,将需要设置的属性值进行base64编码后,再使用setfattr命令设置,注意设置时需在 base64编码前加 0s 前缀。
(5)使用getfattr获取属性后后进行text编码设置。
当未对获取的属性进行编码设置时,直接使用 getfattr -d -m . file.txt 或 getfattr -d file.txt 即可完成
对获取的属性设置text编码时,结果如下:user.age 与 user.hex 的属性值变成了对应的文本值。user.name、user.city、user.base64都仍保留原来的文本值。
(6)使用getfattr获取属性后后进行hex编码设置
user.age 的属性值由八进制变成了十六进制;
user.hex 的属性值还原成了最初设置的原值;
user.name、user.city、user.base64的属性值都转化为对应的十六进制值。
(7)使用getfattr获取属性后后进行base64编码设置
user.age 与user.hex的属性值都保留最初的 base64编码存储;
user.name、user.city、user.base64的属性值都转化为对应的base64编码值。
任务2:注册一个自定义的文件系统类型
查看系统中已经注册的文件系统类型
cat /proc/filesystems
-
使用文件系统注册/注销函数,注册一个自定义文件系统类型;
-
加载模块后,查看系统中是否存在注册的文件系统类型。
-
加载、卸载模块并查看模块打印信息。
源码
register_newfs.c
#include <linux/module.h>
#include <linux/fs.h>
MODULE_LICENSE("GPL");
static struct file_system_type myfs_type = {
.name = "myfs",
.owner = THIS_MODULE,
};
MODULE_ALIAS_FS("myfs");
static int __init register_newfs_init(void)
{
printk("Start register_newfs module...");
return register_filesystem(&myfs_type);
}
static void __exit register_newfs_exit(void)
{
printk("Exit register_newfs module...");
unregister_filesystem(&myfs_type);
}
module_init(register_newfs_init);
module_exit(register_newfs_exit);
Makefile
ifneq ($(KERNELRELEASE),)
obj-m := register_newfs.o
else
KERNELDIR ?= /root/kernel-5.10.0-13.0.0
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
.PHONY:clean
clean:
-rm *.mod.c *.o *.order *.symvers *.ko
运行结果
当未加载内核模块时,当前系统中无自定义的文件系统“myfs”;
当加载内核模块时,当前系统中可打印出自定义的文件系统“myfs”;
当卸载内核模块时,当前系统中无自定义的文件系统“myfs”。
任务3:在/proc下创建目录
-
编写一个模块,在加载模块时,在 /proc目录下创建一个名称为myproc的目录;
-
加载模块后,查看系统中是否在 /proc 目录下成功创建myproc目录。
-
加载、卸载模块并查看模块打印信息。
源码
proc_mkdir.c
#include <linux/module.h>
#include <linux/proc_fs.h>
MODULE_LICENSE("GPL");
static struct proc_dir_entry *myproc_dir;
static int __init myproc_init(void)
{
int ret = 0;
printk("Start proc_mkdir module...");
myproc_dir = proc_mkdir("myproc",NULL);
if(myproc_dir == NULL)
return -ENOMEM;
return ret;
}
static void __exit myproc_exit(void)
{
printk("Exit proc_mkdir module...");
proc_remove(myproc_dir);
}
module_init(myproc_init);
module_exit(myproc_exit);
Makefile
ifneq ($(KERNELRELEASE),)
obj-m := proc_mkdir.o
else
KERNELDIR ?= /root/kernel-5.10.0-13.0.0
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
.PHONY:clean
clean:
-rm *.mod.c *.o *.order *.symvers *.ko
内核模块加载结果
当未加载内核模块时,/proc下无myproc目录;
当加载内核模块时,/proc下可查找到myproc目录。
当卸载内核模块时,/proc下无myproc目录。
任务4:使用sysfs文件系统传递内核模块参数
-
编写一个模块,该模块有三个参数:一个为字符串型,两个为整型。 两个整型中,一个在/sys下不可见。
-
加载模块后,使用echo向模块传递参数值来改变指定参数的值。
-
加载、卸载模块并查看模块打印信息。
源码
sysfs_exam.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/stat.h>
MODULE_LICENSE("GPL");
static int a = 0;
static int b = 0;
static char * c = "Hello, World";
module_param(a, int, 0);
MODULE_PARM_DESC(a, "An invisible int under sysfs");
module_param(b, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(b, "An visible int under sysfs");
module_param(c, charp, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(c, "An visible string under sysfs");
static int __init sysfs_exam_init(void)
{
printk("Start sysfs_exam module...");
printk("a = %d\n", a);
printk("b = %d\n", b);
printk("c = '%s'\n", c);
return 0;
}
static void __exit sysfs_exam_exit(void)
{
printk("Exit sysfs_exam module...");
printk("a = %d\n", a);
printk("b = %d\n", b);
printk("c = '%s'\n", c);
}
module_init(sysfs_exam_init);
module_exit(sysfs_exam_exit);
Makefile
ifneq ($(KERNELRELEASE),)
obj-m := sysfs_exam.o
else
KERNELDIR ?= /root/kernel-5.10.0-13.0.0
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
.PHONY:clean
clean:
-rm *.mod.c *.o *.order *.symvers *.ko
内核模块加载结果
(1)当未加载内核模块时,当前系统中无自定义的内核模块“sysfs_exam”;
当加载内核模块时,当前系统可见自定义的文件系统“sysfs_exam”;
(2)使用modinfo查看内核模块信息,可见a、b、c三个参数的描述:
parm: a:An invisible int under sysfs (int)
parm: b:An visible int under sysfs (int)
parm: c:An visible string under sysfs (charp)
即参数a在/sys中不可见,b、c在/sys中可见,ls -al /sys/module/sysfs_exam/parameters/的输出列表可验证;
(3)可使用echo向模块传递参数值来改变指定参数的值。