实验六、设备管理

1、编写USB设备驱动程序

usb_detect.c:

/*
 * USB Detect driver
 *
 * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
 */
​
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/mutex.h>
​
​
/* Define these values to match your devices */
#define USB_DETECT_VENDOR_ID    0x0951
#define USB_DETECT_PRODUCT_ID   0x160b
​
/* table of devices that work with this driver */
static const struct usb_device_id usbdetect_table[] = {
    { USB_DEVICE(USB_DETECT_VENDOR_ID, USB_DETECT_PRODUCT_ID) },
    { }                 /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, usbdetect_table);
​
​
/* Get a minor range for your devices from the usb maintainer */
#define USB_DETECT_MINOR_BASE   192
​
#define WRITES_IN_FLIGHT    8
/* arbitrarily chosen */
​
/* Structure to hold all of our device specific stuff */
struct usb_detect {
    struct usb_device   *udev;          /* the usb device for this device */
    struct usb_interface    *interface;     /* the interface for this device */
    struct semaphore    limit_sem;      /* limiting the number of writes in progress */
    struct usb_anchor   submitted;      /* in case we need to retract our submissions */
    struct urb      *bulk_in_urb;       /* the urb to read data with */
    unsigned char           *bulk_in_buffer;    /* the buffer to receive data */
    size_t          bulk_in_size;       /* the size of the receive buffer */
    size_t          bulk_in_filled;     /* number of bytes in the buffer */
    size_t          bulk_in_copied;     /* already copied to user space */
    __u8            bulk_in_endpointAddr;   /* the address of the bulk in endpoint */
    __u8            bulk_out_endpointAddr;  /* the address of the bulk out endpoint */
    int         errors;         /* the last request tanked */
    bool            ongoing_read;       /* a read is going on */
    spinlock_t      err_lock;       /* lock for errors */
    struct kref     kref;
    struct mutex        io_mutex;       /* synchronize I/O with disconnect */
    unsigned long       disconnected:1;
    wait_queue_head_t   bulk_in_wait;       /* to wait for an ongoing read */
};
#define to_detect_dev(d) container_of(d, struct usb_detect, kref)
​
static struct usb_driver usbdetect_driver;
​
static void usbdetect_delete(struct kref *kref)
{
    struct usb_detect *dev = to_detect_dev(kref);
​
    usb_free_urb(dev->bulk_in_urb);
    usb_put_intf(dev->interface);
    usb_put_dev(dev->udev);
    kfree(dev->bulk_in_buffer);
    kfree(dev);
}
​
static const struct file_operations usbdetect_fops = {};
​
/*
 * usb class driver info in order to get a minor number from the usb core,
 * and to have the device registered with the driver core
 */
static struct usb_class_driver usbdetect_class = {
    .name =     "usbdetect%d",
    .fops =     &usbdetect_fops,
    .minor_base =   USB_DETECT_MINOR_BASE,
};
​
static int usbdetect_probe(struct usb_interface *interface,
              const struct usb_device_id *id)
{
    struct usb_detect *dev;
    struct usb_endpoint_descriptor *bulk_in, *bulk_out;
    int retval;
​
    /* allocate memory for our device state and initialize it */
    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    if (!dev)
        return -ENOMEM;
​
    kref_init(&dev->kref);
    sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
    mutex_init(&dev->io_mutex);
    spin_lock_init(&dev->err_lock);
    init_usb_anchor(&dev->submitted);
    init_waitqueue_head(&dev->bulk_in_wait);
​
    dev->udev = usb_get_dev(interface_to_usbdev(interface));
    dev->interface = usb_get_intf(interface);
​
    /* set up the endpoint information */
    /* use only the first bulk-in and bulk-out endpoints */
    retval = usb_find_common_endpoints(interface->cur_altsetting,
            &bulk_in, &bulk_out, NULL, NULL);
    if (retval) {
        dev_err(&interface->dev,
            "Could not find both bulk-in and bulk-out endpoints\n");
        goto error;
    }
​
    dev->bulk_in_size = usb_endpoint_maxp(bulk_in);
    dev->bulk_in_endpointAddr = bulk_in->bEndpointAddress;
    dev->bulk_in_buffer = kmalloc(dev->bulk_in_size, GFP_KERNEL);
    if (!dev->bulk_in_buffer) {
        retval = -ENOMEM;
        goto error;
    }
    dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);
    if (!dev->bulk_in_urb) {
        retval = -ENOMEM;
        goto error;
    }
​
    dev->bulk_out_endpointAddr = bulk_out->bEndpointAddress;
​
    /* save our data pointer in this interface device */
    usb_set_intfdata(interface, dev);
​
    /* we can register the device now, as it is ready */
    retval = usb_register_dev(interface, &usbdetect_class);
    if (retval) {
        /* something prevented us from registering this driver */
        dev_err(&interface->dev,
            "Not able to get a minor for this device.\n");
        usb_set_intfdata(interface, NULL);
        goto error;
    }
​
    /* let the user know what node this device is now attached to */
    dev_info(&interface->dev,
         "USB detect device now attached to USBdetect-%d",
         interface->minor);
    return 0;
​
error:
    /* this frees allocated memory */
    kref_put(&dev->kref, usbdetect_delete);
​
    return retval;
}
​
static void usbdetect_disconnect(struct usb_interface *interface)
{
    struct usb_detect *dev;
    int minor = interface->minor;
​
    dev = usb_get_intfdata(interface);
    usb_set_intfdata(interface, NULL);
​
    /* give back our minor */
    usb_deregister_dev(interface, &usbdetect_class);
​
    /* prevent more I/O from starting */
    mutex_lock(&dev->io_mutex);
    dev->disconnected = 1;
    mutex_unlock(&dev->io_mutex);
​
    usb_kill_anchored_urbs(&dev->submitted);
​
    /* decrement our usage count */
    kref_put(&dev->kref, usbdetect_delete);
​
    dev_info(&interface->dev, "USB detect #%d now disconnected", minor);
}
​
static struct usb_driver usbdetect_driver = {
    .name =     "usbdetect",
    .probe =    usbdetect_probe,
    .disconnect =   usbdetect_disconnect,
    .id_table = usbdetect_table,
    .supports_autosuspend = 1,
};
​
MODULE_LICENSE("GPL v2");
​
static int __init usb_detect_init(void)
{
    int result;
    printk("Start usb_detect module...");
    /* register this driver with the USB subsystem */
    result = usb_register(&usbdetect_driver);
    if (result < 0) {
        printk("usb_register failed.""Error number %d", result);
        return -1;
    }
    return 0;
}
​
static void __exit usb_detect_exit(void)
{
    printk("Exit usb_detect module...");
    /* deregister this driver with the USB subsystem */
    usb_deregister(&usbdetect_driver);
}
​
module_init(usb_detect_init);
module_exit(usb_detect_exit);

对usb_detect.c编译运行:

模拟插入U盘:

lsusb指令查看u盘信息:

  • 用法: lsusb [options]

  • 功能:查看/列出USB设备

  • 参数说明:

    -v, --verbose 增加详细程度(显示描述符),列出所有USB的详细

    -s [[bus]:][devnum] 仅显示具有指定设备和/或总线号的设备(十进制)

    -d vendor:[product] 仅显示具有指定供应商和产品ID号(十六进制)的设备

    -D device 选择lsusb将检查的设备

    -t, --tree 将物理USB设备层次结构转储为树

    -V, --version 显示程序版本

    -h, --help 显示用法和帮助

查看U盘信息:

插拔一次U盘,设备号加1:

拔出U盘,查看打印信息,发现5号usb已经断开:

查看U盘信息:

卸载模块:

2、编写内核模块测试硬盘的读写速率,并与 iozone工具的测试结果比较

相关内核函数:

  • filp_open() //打开文件

  • filp_close() //关闭文件

  • kernel_read() //读文件

  • kernel_write() //写文件

使用IOZONE工具测试读写速度:

最近刚好了解到ssh远程登录,在此尝试使用windows主机cmd来登录openeuler虚拟机:

查看内存大小:

读写测试:

最小测试文件设置为512M,最大4G,并生成xls文件。

运行结果报告:

write_to_disk.c:

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/rtc.h>
​
#define buf_size 1024
#define write_times 524288
​
MODULE_LICENSE("GPL");
​
struct timeval tv;
​
static int __init write_disk_init(void)
{
    struct file *fp_write;
    char buf[buf_size];
    int i;
    int write_start_time;
    int write_start_time_u;
    int write_end_time;
    int write_end_time_u;
    int write_time;
    loff_t pos;
    printk("Start write_to_disk module...\n");
    for(i = 0; i < buf_size; i++)
    {
        buf[i] = i + '0';
    }
    fp_write = filp_open("/home/tmp_file", O_RDWR | O_CREAT,0644);
    if (IS_ERR(fp_write)) {
        printk("Failed to open file...\n");
        return -1;
    }
    pos = 0;
    do_gettimeofday(&tv);
    write_start_time = (int)tv.tv_sec;
    write_start_time_u = (int)tv.tv_usec;
    for(i = 0; i < write_times; i++) {
        kernel_write(fp_write, buf, buf_size, &pos);
    }
    do_gettimeofday(&tv);
    write_end_time = (int)tv.tv_sec;
    write_end_time_u = (int)tv.tv_usec;
    filp_close(fp_write, NULL);
    write_time = (write_end_time - write_start_time)  * 1000000 + (write_end_time_u - write_start_time_u);
    printk(KERN_ALERT "Writing to file costs %d us\n", write_time); 
    printk("Writing speed is %d M/s\n", buf_size * write_times / write_time);
    return 0;
}
​
static void __exit write_disk_exit(void)
{
    printk("Exit write_to_disk module...\n");
}
​
module_init(write_disk_init);
module_exit(write_disk_exit);

测试写速度:

得出写速率为17M/s。

read_from_disk.c:

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/rtc.h>
​
#define buf_size 1024
#define read_times 524288
​
MODULE_LICENSE("GPL");
​
struct timeval tv;
​
static int __init read_disk_init(void)
{
    struct file *fp_read;
    char buf[buf_size];
    int i;
    int read_start_time;
    int read_start_time_u;
    int read_end_time;
    int read_end_time_u;
    int read_time;
    loff_t pos;
    printk("Start read_from_disk module...\n");
    fp_read = filp_open("/home/tmp_file", O_RDONLY, 0);
    if (IS_ERR(fp_read)) {
        printk("Failed to open file...\n");
        return -1;
    }
​
    do_gettimeofday(&tv);
    read_start_time = (int)tv.tv_sec;
    read_start_time_u = (int)tv.tv_usec;
    pos = 0;
    for(i = 0; i < read_times; i++) {
        kernel_read(fp_read, buf, buf_size, &pos);
    }
    do_gettimeofday(&tv);
    read_end_time = (int)tv.tv_sec;
    read_end_time_u = (int)tv.tv_usec;
    filp_close(fp_read, NULL);
    read_time = (read_end_time - read_start_time)  * 1000000 + (read_end_time_u - read_start_time_u);
    printk(KERN_ALERT "Read file costs %d us\n", read_time);    
    printk("Reading speed is %d M/s\n", buf_size * read_times / read_time);
    return 0;
}
​
static void __exit read_disk_exit(void)
{
    printk("Exit read_from_disk module...\n");
}
​
module_init(read_disk_init);
module_exit(read_disk_exit);

测试读速度:

读速率为2932M/s。

用户态的读写速率比内核态更慢。

原因说明:

内核态:CPU可以访问内存所有数据, 包括外围设备, 例如硬盘、网卡;CPU也可以将自己从一个程序切换到另一个程序

用户态:只能受限的访问内存, 且不允许访问外围设备;占用CPU的能力被剥夺,CPU资源可以被其他程序获取。

也就是说:内核态的程序可以直接读写硬盘;而用户态的程序需要先切换至内核态,再由内核态进行系统调用来读写磁盘。因此,用户态的硬盘读写速率比内核态更耗时。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

天涯若

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

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

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

打赏作者

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

抵扣说明:

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

余额充值