【OS】实验七:文件系统

911 阅读5分钟

实验七:文件系统

任务1:为 Ext4 文件系统添加扩展属性

文件扩展属性的使用

1、环境准备

为了使用扩展属性,需要安装 libattr:

2、如何查看当前文件系统类型

df -Th

image-20211226155639666

3、检查当前文件系统是否支持文件扩展属性

(1)用 fdisk -l 查看硬盘及分区信息

image-20211226155907882

(2)用 tune2fs -l 显示设备的详细信息

image-20211226160137955

image-20211226160233022

通过检查/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为前缀。

任务描述

  1. 使用setfattr设置文件系统的用户扩展属性,并设置文本、八进制数、十六进制数与base64编码这四种属性值。

  2. 使用getfattr获取文件系统的用户扩展属性,并在获取属性之后进行text、hex和base64这三种编码设置。

(1)对于不含转义字符 \ 的纯文本属性值

有无双引号限定效果一样

image-20211226161603020

(2)对于包含转义字符 \ 的文本属性值

无双引号则不对转义符 \ 进行转义;有双引号则对其进行转义。

例如:设置八进制数时,设置属性值为 \012 时,最终识别为文本012;设置属性值为“\012”时,最终以八进制数的base64编码存储。

image-20211226161810067

(3)设置属性值为十六进制数时

所设置的数的位数必须为偶数,即0x 或 0X后的数字必须为偶数位,否则出错。 若设置成功,最终以十六进制数的base64编码存储。

image-20211226162119034

(4)设置属性值为base64编码时

所设置的编码必须符合base64编码,即0s后的编码字符串必须符合base64编码,否则出错。 若设置成功,最终以base64编码对应的文本信息存储。

tips:可在base64.us/ 中,将需要设置的属性值进行base64编码后,再使用setfattr命令设置,注意设置时需在 base64编码前加 0s 前缀。

image-20211226162412317

image-20211226162405221

(5)使用getfattr获取属性后后进行text编码设置。

当未对获取的属性进行编码设置时,直接使用 getfattr -d -m . file.txt 或 getfattr -d file.txt 即可完成

image-20211226162542026

对获取的属性设置text编码时,结果如下:user.age 与 user.hex 的属性值变成了对应的文本值。user.name、user.city、user.base64都仍保留原来的文本值。

image-20211226162839796

(6)使用getfattr获取属性后后进行hex编码设置

image-20211226162923025

user.age 的属性值由八进制变成了十六进制;

user.hex 的属性值还原成了最初设置的原值;

user.name、user.city、user.base64的属性值都转化为对应的十六进制值。

(7)使用getfattr获取属性后后进行base64编码设置

image-20211226162958177

user.age 与user.hex的属性值都保留最初的 base64编码存储;

user.name、user.city、user.base64的属性值都转化为对应的base64编码值。

image-20211226163152676

image-20211226163212188

任务2:注册一个自定义的文件系统类型

查看系统中已经注册的文件系统类型

cat /proc/filesystems

image-20211226163818691

  1. 使用文件系统注册/注销函数,注册一个自定义文件系统类型;

  2. 加载模块后,查看系统中是否存在注册的文件系统类型。

  3. 加载、卸载模块并查看模块打印信息。

源码

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

运行结果

image-20211226165315594

当未加载内核模块时,当前系统中无自定义的文件系统“myfs”;

当加载内核模块时,当前系统中可打印出自定义的文件系统“myfs”;

当卸载内核模块时,当前系统中无自定义的文件系统“myfs”。

任务3:在/proc下创建目录

  1. 编写一个模块,在加载模块时,在 /proc目录下创建一个名称为myproc的目录;

  2. 加载模块后,查看系统中是否在 /proc 目录下成功创建myproc目录。

  3. 加载、卸载模块并查看模块打印信息。

源码

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

内核模块加载结果

image-20211226170624482

当未加载内核模块时,/proc下无myproc目录;

当加载内核模块时,/proc下可查找到myproc目录。

当卸载内核模块时,/proc下无myproc目录。

任务4:使用sysfs文件系统传递内核模块参数

  1. 编写一个模块,该模块有三个参数:一个为字符串型,两个为整型。 两个整型中,一个在/sys下不可见。

  2. 加载模块后,使用echo向模块传递参数值来改变指定参数的值。

  3. 加载、卸载模块并查看模块打印信息。

源码

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”;

image-20211226171828274

(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/的输出列表可验证;

image-20211226171947842

image-20211226172052410

(3)可使用echo向模块传递参数值来改变指定参数的值。

image-20211226172249769