和字符驅動相比 ,在對磁盤,flash等設備進行讀寫時,塊設備驅動可以進行優化合並等操作,提高了操作效率。
以下代碼來自linux-2.6.38。LDD3電子書網頁版的地址:http://oss.org.cn/kernel-book/ldd3/
一、註冊
這個任務的函數是 register_blkdev(在 <linux/fs.h> 中定義):
int register_blkdev(unsigned int major, const char *name)
參數是你的設備要使用的主編號和關聯的名子(內核將顯示它在 /proc/devices). 如果 major 傳遞爲0,
內核分配一個新的主編號並且返回它給調用者. 如常, 自 register_blkdev 的一個負的返回值指示已發生了一個錯誤.
取消註冊的對應函數是:
int unregister_blkdev(unsigned int major, const char *name);
這裏, 參數必須匹配傳遞給 register_blkdev 的那些, 否則這個函數返回 -EINVAL 並且什麼都不註銷.
在2.6內核, 對 register_blkdev 的調用完全是可選的. 由 register_blkdev 所進行的功能已隨時間正在減少;
這個調用唯一的任務是 (1) 如果需要, 分配一個動態主編號, 並且 (2) 在 /proc/devices 創建一個入口. 在將來的內核,
register_blkdev 可能被一起去掉. 同時, 但是, 大部分驅動仍然調用它; 它是慣例.
字符設備通過 file_ 操作結構使它們的操作對系統可用. 一個類似的結構用在塊設備上; 它是 struct block_device_operations, 定義在 <linux/fs.h>. 下面是一個對這個結構中的成員的簡短的概覽; 當我們進入 sbull 驅動的細節時詳細重新訪問它們.
int (*open)(struct inode *inode, struct file *filp);
int (*release)(struct inode *inode, struct file *filp);
就像它們的字符驅動對等體一樣工作的函數; 無論何時設備被打開和關閉都調用它們. 一個字符驅動可能通過啓動設備或者鎖住門(爲可移出的介質)來響應一個 open 調用. 如果你將介質鎖入設備, 你當然應當在 release 方法中解鎖.
int (*ioctl)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
實現 ioctl 系統調用的方法. 但是, 塊層首先解釋大量的標準請求; 因此大部分的塊驅動 ioctl 方法相當短.
int (*media_changed) (struct gendisk *gd);
被內核調用來檢查是否用戶已經改變了驅動器中的介質的方法, 如果是這樣返回一個非零值. 顯然, 這個方法僅適用於支持可移出的介質的驅動器(並且最好給驅動一個"介質被改變"標誌); 在其他情況下可被忽略.
struct gendisk 參數是內核任何表示單個磁盤; 我們將在下一節查看這個結構.
int (*revalidate_disk) (struct gendisk *gd);
revalidate_disk 方法被調用來響應一個介質改變; 它給驅動一個機會來進行需要的任何工作使新介質準備好使用. 這個函數返回一個 int 值, 但是值被內核忽略.
struct module *owner;
一個指向擁有這個結構的模塊的指針; 它應當常常被初始化爲 THIS_MODULE.
專心的讀者可能已注意到這個列表一個有趣的省略: 沒有實際讀或寫數據的函數. 在塊 I/O 子系統, 這些操作由請求函數處理, 它們應當有它們自己的一節並且在本章後面討論. 在我們談論服務請求之前, 我們必須完成對磁盤註冊的討論.
2 int (*open) (struct block_device *, fmode_t);
3 int (*release) (struct gendisk *, fmode_t);
4 int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
5 int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
6 int (*direct_access) (struct block_device *, sector_t,
7 void **, unsigned long *);
8 unsigned int (*check_events) (struct gendisk *disk,
9 unsigned int clearing);
10 /* ->media_changed() is DEPRECATED, use ->check_events() instead */
11 int (*media_changed) (struct gendisk *);
12 void (*unlock_native_capacity) (struct gendisk *);
13 int (*revalidate_disk) (struct gendisk *);
14 int (*getgeo)(struct block_device *, struct hd_geometry *);
15 /* this callback is with swap_lock and sometimes page table lock held */
16 void (*swap_slot_free_notify) (struct block_device *, unsigned long);
17 struct module *owner;
18 };
三、gendisk 結構
struct gendisk (定義於 <linux/genhd.h>) 是單獨一個磁盤驅動器的內核表示。
1 struct gendisk { 2 /* major, first_minor and minors are input parameters only, 3 * don't use directly. Use disk_devt() and disk_max_parts(). 4 */ 5 int major; /* major number of driver */ 6 int first_minor; 7 int minors; /* maximum number of minors, =1 for 8 * disks that can't be partitioned. */ 9 10 char disk_name[DISK_NAME_LEN]; /* name of major driver */ 11 char *(*devnode)(struct gendisk *gd, mode_t *mode); 12 13 unsigned int events; /* supported events */ 14 unsigned int async_events; /* async events, subset of all */ 15 16 /* Array of pointers to partitions indexed by partno. 17 * Protected with matching bdev lock but stat and other 18 * non-critical accesses use RCU. Always access through 19 * helpers. 20 */ 21 struct disk_part_tbl __rcu *part_tbl; 22 struct hd_struct part0; 23 24 const struct block_device_operations *fops; 25 struct request_queue *queue; 26 void *private_data; 27 28 int flags; 29 struct device *driverfs_dev; // FIXME: remove 30 struct kobject *slave_dir; 31 32 struct timer_rand_state *random; 33 atomic_t sync_io; /* RAID */ 34 struct disk_events *ev; 35 #ifdef CONFIG_BLK_DEV_INTEGRITY 36 struct blk_integrity *integrity; 37 #endif 38 int node_id; 39 };