操作系统实验-设备管理
前言
- 使用vim编写代码,具体操作参考前文进程管理部分
实验操作
任务一:编写USB设备驱动程序
首先插上u盘查看相关信息以便后续编写代码
# 获取u盘vid和pid
lsusb

如图,vid为090c,pid为2000
设备名称为后面Silicon那一长串
编写相关代码:
- usb_detect.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/usb.h>
/* 定义你的U盘的Vendor ID和Product ID */
#define USB_DETECT_VENDOR_ID 0x090c // u盘vid
#define USB_DETECT_PRODUCT_ID 0x2000 // u盘pid
/* 支持的设备列表 */
static const struct usb_device_id usbdetect_table[] = {
{ USB_DEVICE(USB_DETECT_VENDOR_ID, USB_DETECT_PRODUCT_ID) },
{ } /* 终止项 */
};
MODULE_DEVICE_TABLE(usb, usbdetect_table);
/* 探测函数 - 当设备插入时调用 */
static int usbdetect_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(interface);
printk(KERN_INFO "USB Device Inserted: VID=0x%04x, PID=0x%04x\n",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
return 0; /* 返回0表示驱动接受该设备 */
}
/* 断开函数 - 当设备拔出时调用 */
static void usbdetect_disconnect(struct usb_interface *interface)
{
struct usb_device *udev = interface_to_usbdev(interface);
printk(KERN_INFO "USB Device Removed: VID=0x%04x, PID=0x%04x\n",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
}
/* USB驱动结构体 */
static struct usb_driver usbdetect_driver = {
.name = "usb_detect", /* 驱动名称 */
.probe = usbdetect_probe, /* 设备插入时调用 */
.disconnect = usbdetect_disconnect, /* 设备拔出时调用 */
.id_table = usbdetect_table, /* 支持的设备列表 */
};
/* 模块初始化函数 */
static int __init usb_detect_init(void)
{
int ret;
printk(KERN_INFO "USB Detect Driver: Initializing...\n");
/* 注册USB驱动 */
ret = usb_register(&usbdetect_driver);
if (ret < 0) {
printk(KERN_ERR "USB Detect Driver: Registration failed (%d)\n", ret);
return ret;
}
printk(KERN_INFO "USB Detect Driver: Registered successfully\n");
return 0;
}
/* 模块退出函数 */
static void __exit usb_detect_exit(void)
{
printk(KERN_INFO "USB Detect Driver: Unregistering...\n");
/* 注销USB驱动 */
usb_deregister(&usbdetect_driver);
printk(KERN_INFO "USB Detect Driver: Unregistered\n");
}
module_init(usb_detect_init);
module_exit(usb_detect_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Simple USB Device Detection Driver");
- Makefile
obj-m := usb_detect.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
编译驱动
make
加载驱动并查看日志
sudo insmod usb_detect.ko
dmesg | tail

我在模块加载完成后并不能正常输出,排查后发现是因为usb设备被usb_storage驱动占用,卸载相关驱动后重新插拔U盘,输出如下,可以看到USB插拔过程中能检测并输出提示

任务二:编写内核模块测试硬盘的读写速率,并与 iozone工具的测试结果比较,并分析结果差异原因
编写内核模块测试硬盘读写速率
编写相关代码:
- test.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/ktime.h>
#include <linux/namei.h>
#include <linux/file.h>
#include <linux/fcntl.h>
#define FILE_SIZE (512 * 1024 * 1024) // 512MB
#define MY_BLOCK_SIZE (1024) // 1KB,避免与内核BLOCK_SIZE冲突
#define TEST_FILE "/tmp/disk_bench_testfile"
static char *buffer;
static int __init disk_benchmark_init(void) {
struct file *filp;
loff_t pos;
ktime_t start, end;
s64 write_time, read_time;
ssize_t ret;
size_t written, readed;
buffer = kmalloc(MY_BLOCK_SIZE, GFP_KERNEL);
if (!buffer) {
printk(KERN_ERR "Failed to allocate memory for buffer\n");
return -ENOMEM;
}
memset(buffer, 'A', MY_BLOCK_SIZE);
// 写测试
filp = filp_open(TEST_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (IS_ERR(filp)) {
printk(KERN_ERR "Failed to open file for write test\n");
kfree(buffer);
return -EIO;
}
pos = 0;
written = 0;
start = ktime_get();
while (written < FILE_SIZE) {
size_t to_write = MY_BLOCK_SIZE;
if (FILE_SIZE - written < MY_BLOCK_SIZE)
to_write = FILE_SIZE - written;
ret = kernel_write(filp, buffer, to_write, &pos);
if (ret < 0) break;
written += ret;
}
end = ktime_get();
filp_close(filp, NULL);
write_time = ktime_to_ns(ktime_sub(end, start));
if (ret < 0)
printk(KERN_ERR "Write error: %zd\n", ret);
else
printk(KERN_INFO "Write test: %zu bytes, %lld ns, %lld KB/s\n",
written, write_time,
write_time ? (written * 1000000000LL / write_time / 1024) : 0);
// 读测试
filp = filp_open(TEST_FILE, O_RDONLY, 0);
if (IS_ERR(filp)) {
printk(KERN_ERR "Failed to open file for read test\n");
kfree(buffer);
return -EIO;
}
pos = 0;
readed = 0;
start = ktime_get();
while (readed < FILE_SIZE) {
size_t to_read = MY_BLOCK_SIZE;
if (FILE_SIZE - readed < MY_BLOCK_SIZE)
to_read = FILE_SIZE - readed;
ret = kernel_read(filp, buffer, to_read, &pos);
if (ret <= 0) break;
readed += ret;
}
end = ktime_get();
filp_close(filp, NULL);
read_time = ktime_to_ns(ktime_sub(end, start));
if (ret < 0)
printk(KERN_ERR "Read error: %zd\n", ret);
else
printk(KERN_INFO "Read test: %zu bytes, %lld ns, %lld KB/s\n",
readed, read_time,
read_time ? (readed * 1000000000LL / read_time / 1024) : 0);
kfree(buffer);
return 0;
}
static void __exit disk_benchmark_exit(void) {
printk(KERN_INFO "Disk benchmark module unloaded\n");
}
module_init(disk_benchmark_init);
module_exit(disk_benchmark_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple disk benchmark kernel module");
MODULE_VERSION("1.0");
- Makefile
obj-m += test.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
编译后加载内核,查看日志看到测速信息

使用iozone工具测速
安装iozone
# 直接安装显示no match了,所以从直接下载源码编译了
# 编译工具,编译内核的时候应该下过?
sudo dnf install gcc make wget tar
# 下载源码
wget https://www.iozone.org/src/current/iozone3_507.tar
# 解压并编译
tar xf iozone3_508.tar
cd iozone3_508/src/current
make linux
指导书上输入命令如下
./iozone -Raz -n 512m -g 16g -r 1k -y 1k -i 0 -i 1 -b /usr/src/kernels/iozone.xls
其中 -g 参数后为最大测试文件大小, 修改为内存大小的两倍以避免缓存影响
输出路径我不是很清楚为什么要放在这个文件,就直接放在当前目录以便后续处理了
按照我自己的配置修改命令如下
./iozone -Raz -n 512m -g 8g -r 1k -y 1k -i 0 -i 1 -b ./iozone.xls
还挺慢的,搞了差不多二十分钟

其中读写速度分别为(不是很理解为什么要导出到xls文件中,内容与控制台输出是一致的):


上述数据单位为KB/s

浙公网安备 33010602011771号