zoukankan      html  css  js  c++  java
  • 12.块设备驱动程序(磁盘)

    1.小结

    1. 分配gendisk结构
    2. 分配设置队列,队列提供实际的读写函数,这个会赋值到gendisk
    3. 注册块设备驱动(对比注册字符设备驱动,并没有提供一个file_operations
    4. 设置gendisk参数,包括先前的队列
    5. 注册这个gendisk

    2.关键函数解析

    • register_blkdev
      注册块设备

      int register_blkdev(unsigned int major, const char *name)            //如果major为0则为其自动分配主设备号
      
    • gendisk
      磁盘设备

      struct gendisk {
        int major;			/* major number of driver */
        int first_minor;
        int minors;                     /* maximum number of minors, =1 for
                                             * disks that can't be partitioned. 分区此设备数,在alloc_disk中分配*/
        char disk_name[DISK_NAME_LEN];	/* name of major driver */
        char *(*devnode)(struct gendisk *gd, umode_t *mode);
      
        unsigned int events;		/* supported events */
        unsigned int async_events;	/* async events, subset of all */
      
        /* Array of pointers to partitions indexed by partno.
         * Protected with matching bdev lock but stat and other
         * non-critical accesses use RCU.  Always access through
         * helpers.
         */
        struct disk_part_tbl __rcu *part_tbl;
        struct hd_struct part0;                  //分区表信息
      
        const struct block_device_operations *fops;      //块设备的操作函数
        struct request_queue *queue;                  //请求队列,用于管理设备IO请求队列的指针
        void *private_data;                           //私有数据
      
        int flags;
        struct device *driverfs_dev;  // FIXME: remove
        struct kobject *slave_dir;
      
        struct timer_rand_state *random;
        atomic_t sync_io;		/* RAID */
        struct disk_events *ev;
      #ifdef  CONFIG_BLK_DEV_INTEGRITY
        struct blk_integrity *integrity;
      #endif
        int node_id;
      };
      
    • void set_capacity(struct gendisk *disk, sector_t size)
      设置扇区数。512位一个扇区,描述设备容量

      static inline void set_capacity(struct gendisk *disk, sector_t size)
      {
          disk->part0.nr_sects = size;
      }
      

    3.代码解析

    static struct gendisk *ramblock_disk;
    static request_queue_t *ramblock_queue;
    
    static int major;
    
    static DEFINE_SPINLOCK(ramblock_lock);
    
      #define RAMBLOCK_SIZE (1024*1024)
    static unsigned char *ramblock_buf;
    
    static int ramblock_getgeo(struct block_device *bdev, struct hd_geometry *geo)
    {
    	/* 容量=heads*cylinders*sectors*512 */
    	geo->heads     = 2;
    	geo->cylinders = 32;
    	geo->sectors   = RAMBLOCK_SIZE/2/32/512;
    	return 0;
    }
    
    
    static struct block_device_operations ramblock_fops = {
    	.owner	= THIS_MODULE,
    	.getgeo	= ramblock_getgeo,
    };
    
    static void do_ramblock_request(request_queue_t * q)
    {
    	static int r_cnt = 0;
    	static int w_cnt = 0;
    	struct request *req;
    	
    	//printk("do_ramblock_request %d
    ", ++cnt);
    
    	while ((req = elv_next_request(q)) != NULL) {            //电梯算法
    		/* 数据传输三要素: 源,目的,长度 */
    		/* 源/目的: */
    		unsigned long offset = req->sector * 512;
    
    		/* 目的/源: */
    		// req->buffer
    
    		/* 长度: */		
    		unsigned long len = req->current_nr_sectors * 512;
    
    		if (rq_data_dir(req) == READ)
    		{
    			//printk("do_ramblock_request read %d
    ", ++r_cnt);
    			memcpy(req->buffer, ramblock_buf+offset, len);
    		}
    		else
    		{
    			//printk("do_ramblock_request write %d
    ", ++w_cnt);
    			memcpy(ramblock_buf+offset, req->buffer, len);
    		}		
    		
    		end_request(req, 1);
    	}
    }
    
    static int ramblock_init(void)
    {
    	/* 1. 分配一个gendisk结构体 */
    	ramblock_disk = alloc_disk(16); /* 次设备号个数: 分区个数+1 */
    
    	/* 2. 设置 */
    	/* 2.1 分配/设置队列: 提供读写能力 */
    	ramblock_queue = blk_init_queue(do_ramblock_request, &ramblock_lock);            //do_ramblock_request具体的读写函数
    	ramblock_disk->queue = ramblock_queue;
    	
    	/* 2.2 设置其他属性: 比如容量 */
    	major = register_blkdev(0, "ramblock");  /* cat /proc/devices */	
    	ramblock_disk->major       = major;
    	ramblock_disk->first_minor = 0;
    	sprintf(ramblock_disk->disk_name, "ramblock");
    	ramblock_disk->fops        = &ramblock_fops;
    	set_capacity(ramblock_disk, RAMBLOCK_SIZE / 512);
    
    	/* 3. 硬件相关操作 */
    	ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);            //kzalloc申请内存外还会清零
    
    	/* 4. 注册 */
    	add_disk(ramblock_disk);
    
    	return 0;
    }
    
    static void ramblock_exit(void)
    {
    	unregister_blkdev(major, "ramblock");
    	del_gendisk(ramblock_disk);
    	put_disk(ramblock_disk);
    	blk_cleanup_queue(ramblock_queue);
    
    	kfree(ramblock_buf);
    }
    
    module_init(ramblock_init);
    module_exit(ramblock_exit);
    
    MODULE_LICENSE("GPL");
  • 相关阅读:
    docker compose示例
    mysql表分区案例
    mysql表分区实战
    mysql分表
    MongoDB基础教程系列--目录结构
    如何优化Mysql千万级快速分页,limit优化快速分页,MySQL处理千万级数据查询的优化方案
    网站性能压力测试工具--apache ab使用详解
    tomcat8 JVM 优化
    tomcat8 性能优化
    redis.properties
  • 原文地址:https://www.cnblogs.com/huangdengtao/p/13557180.html
Copyright © 2011-2022 走看看