ブロックデバイスドライバ(3) - シンプルなデザインのブロック・デバイス・ドライバ

このレッスンでは、主に、初期化ブロックとレッスンのうち動作フロー解析装置によれば、独自のデバイスドライバの機能ブロックを書き込みます。だから、このブログは、使用される他のフレームワークの使用および機能について話を主にあります。

  • 図1に示すように、モジュール枠の調製
  • 図2に示すように、ブロックデバイス登録主要= register_blkdev(メジャー、「BLKを 」); これは、2つのパラメータ、マスタデバイス番号とデバイス名を持っているので、ここではパラメータが0である一般的に、自動的に割り当てられたコアを使用し、自動分配装置の数が返され得られた値です。戻り値は、メジャー番号の割り当てに失敗したエラーメッセージを示す、0以下であると-EBUSY(マクロは<linux / ERRNO.H> IN)を返した場合。2番目のパラメータは、デバイスの名前です。
  • 3、完全に他の初期化、の定義setup_deviceの機能を実現しています。
    • 3.1コンピューティングデバイスのブロックサイズ
    • /计算设备大小
      dev->size = nsectors*sect_size;
      dev->data = vmalloc(dev->size);
      3.2を使用して、要求キューを開始DEV->キュー= blk_init_queueを(blk_request、NULL);、最初のパラメータは、要求に応じて関数であり、これは2番目のパラメータはスピンロックは、一般的に空である、blk_requestとして定義されます。戻り値は、我々がキューを保持するための構造を定義所有するキューのアドレスです。
    • struct blk_dev{
          int size;                        /* Device size in sectors */
          u8 *data;                        /* The data array */
          struct request_queue *queue;     /* The device request queue */
          struct gendisk *gd;              /* The gendisk structure */
      };
      
      良いの定義がなければならない後blk_init関数のための空間構造を適用DEV = kmallocの(はsizeof(構造体blk_dev )、GFP_KERNEL)。
    • 3.3 blk_queue_logical_block_size指定された機器のセクタサイズ、サイズパラメータは、ブロックと、要求キューであります
    • 割り当て3.4 gendisk割り当てられた構造は、各装置が使用して、カーネル内の指定されたブロック構造gendiskを有する(1)DEV->のGd = alloc_diskと、パラメータは、1つの簡略化のために満たすことができるデバイスを、サポートすることができるどのように多くのデバイスのブロックを示しています。保存されたリターンgendiskポインタ。
    • 3.5 gendisk構造体の初期化を完了します。
  • // 初始化gendisk结构
    dev->gd->major = major; //主设备号
    dev->gd->first_minor = 0; //次设备号
    dev->gd->fops = &blk_ops; //操作函数集
    dev->gd->queue = dev->queue; //请求队列
    dev->gd->private_data = dev; //私有数据
    sprintf(dev->gd->disk_name, "simp_blk%d", 0); //磁盘名字
    set_capacity(dev->gd, nsectors*(sect_size / sect_size)); //分配扇区数
    4、ブロックライト機能デバイスリクエスト静的な無効blk_request(構造体request_queueのQ *) パラメータが要求キューであります
    • 要求キューのうち4.1要求、(Q)blk_fetch_request REQ = ;あなたが説明した空取得しない場合は、要求を処理し、その後、キューが空であるかどうかを判断し、そうでない場合は、空の2番目のリクエストを処理します。ここによるハンドラblk_transferを達成しました。
  • 図5に示すように、ブロック書き込みデバイスハンドラblk_transferパラメータは、DEVインタフェースを操作開始セクタセクタ操作の数ストアデータバッファ構造その後の読み取りと書き込みステータス
    • blk_transfer(DEV、blk_rq_pos(REQ)、blk_rq_cur_sectors(REQ)、req->バッファ、rq_data_dir(REQ))。
  • 図6に示すように、プログラムを終了するブロックデバイスの製造
    • 6.1キャンセルgendiskdel_gendisk(DEV-> GD);
    • 6.2クリアキューblk_cleanup_queue(DEV->キュー)。
    • 6.3割り当てられた領域の解放vfree(DEV->データ)。
    • 6.4キャンセルブロックデバイスunregister_blkdev(メジャー、 "BLK") 。
    • DEV 6.5リリース構造kfree(DEV)。
  • 完全なコード
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/blkdev.h>
#include <linux/bio.h>

static int major = 0;
static int sect_size = 512;   // 扇区大小
static int nsectors = 1024;  // 扇区数

struct blk_dev
{
	int size;
	u8 *data;
	struct request_queue *queue;
	struct gendisk *gd;		
};

struct blk_dev *dev;

static struct block_device_operations blk_ops = 
{
	.owner = THIS_MODULE,
};

void blk_transfer(struct blk_dev *dev, unsigned long sector, unsigned long nsect, char *buffer, int write)
{
	unsigned long offset = sector * sect_size; // 操作的起始地址
	unsigned long nbytes = nsect * sect_size;  // 操作的数据量
	
	if (write)
		memcpy (dev->data + offset, buffer, nbytes);
	else
		memcpy (buffer, dev->data + offset, nbytes);
}

static void blk_request(struct request_queue *q)
{
	struct request *req;
	
	// 从队列中取出一个请求
	req = blk_fetch_request(q);	
	
	while (req != NULL)
	{
		// 处理该请求
		blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));
		
		if (!__blk_end_request_cur(req, 0))
			req = blk_fetch_request(q);			
	}	
}
	
void setup_device()
{
	// 计算块设备的大小
	dev->size = nsectors * sect_size; 
	dev->data = vmalloc(dev->size);		

	// 初始化一个请求队列
	dev->queue = blk_init_queue(blk_request, NULL);
	
	// 指明设备的扇区大小,参数分别为请求队列和块的大小
	blk_queue_logical_block_size(dev->queue, sect_size);
	
	// 分配gendisk结构
	dev->gd = alloc_disk(1);
	
	// 初始化gendisk结构
	dev->gd->major = major; //主设备号
	dev->gd->first_minor = 0; //次设备号
	dev->gd->fops = &blk_ops; //操作函数集
	dev->gd->queue = dev->queue; //请求队列
	dev->gd->private_data = dev; //私有数据
	sprintf(dev->gd->disk_name, "simp_blk%d", 0); //磁盘名字
	set_capacity(dev->gd, nsectors*(sect_size / sect_size)); //分配扇区数
	
	// 注册gendisk
	add_disk(dev->gd);
}

int blk_init()
{
	 // 注册一个块设备
	major = register_blkdev(0, "blk");	
	
	if (major <= 0)
	{
		printk("register blk dev fail!\n");	
		return -EBUSY;	
	}
	
	dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL);
		
	setup_device();
		
	return 0;	
}

void blk_exit()
{
	del_gendisk(dev->gd);
	blk_cleanup_queue(dev->queue);
	vfree(dev->data);
	unregister_blkdev(major, "blk");
	kfree(dev);
}

module_init(blk_init);
module_exit(blk_exit);

 

おすすめ

転載: blog.csdn.net/qq_22847457/article/details/93975105