看完了 block 子系统的初始化之后 , 我曾一度迷茫过 , 也曾辗转反侧 , 也曾苦恼万分 , 我完全不知道下一步该怎么走 , 几经思索 , 思索着我和中国的未来 , 徘徊过后 , 彷徨过后 , 终于决定 , 和 scsi disk 驱动同步进行往下走 , 因为 scsi disk 那边会调用许多 block 层这边提供的函数 , 于是我们就在这边来看看这些函数究竟是干什么的 .
第一个函数当然就是 register_blkdev().
55 int register_blkdev(unsigned int major, const char *name)
56 {
57 struct blk_major_name **n, *p;
58 int index, ret = 0;
59
60 mutex_lock(&block_subsys_lock);
61
62 /* temporary */
63 if (major == 0) {
64 for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {
65 if (major_names[index] == NULL)
66 break;
67 }
68
69 if (index == 0) {
70 printk("register_blkdev: failed to get major for %s/n",
71 name);
72 ret = -EBUSY;
73 goto out;
74 }
75 major = index;
76 ret = major;
77 }
78
79 p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL);
80 if (p == NULL) {
81 ret = -ENOMEM;
82 goto out;
83 }
84
85 p->major = major;
86 strlcpy(p->name, name, sizeof(p->name));
87 p->next = NULL;
88 index = major_to_index(major);
89
90 for (n = &major_names[index]; *n; n = &(*n)->next) {
91 if ((*n)->major == major)
92 break;
93 }
94 if (!*n)
95 *n = p;
96 else
97 ret = -EBUSY;
98
99 if (ret < 0) {
100 printk("register_blkdev: cannot get major %d for %s/n",
101 major, name);
102 kfree(p);
103 }
104 out:
105 mutex_unlock(&block_subsys_lock);
106 return ret;
107 }
从 sd 那边调用这个函数来看 , 咱们是指定了主设备号了的 . 换言之 , 这里的 major 是非零值 , 而 struct blk_major_name 的定义也在 block/genhd.c 中 :
27 static struct blk_major_name {
28 struct blk_major_name *next;
29 int major;
30 char name[16];
31 } *major_names[BLKDEV_MAJOR_HASH_SIZE];
注意这里顺便定义了一个数组 major_names, 咱们这里也用到了 .
这其中 BLKDEV_MAJOR_HASH_SIZE 定义于 include/linux/fs.h:
1575 #define BLKDEV_MAJOR_HASH_SIZE 255
即数组 major_names[] 有 255 个元素 , 换言之 , 咱们定义了 255 个指针 .
而 88 行这个内联函数同样来自 block/genhd.c:
33 /* index in the above - for now: assume no multimajor ranges */
34 static inline int major_to_index(int major)
35 {
36 return major % BLKDEV_MAJOR_HASH_SIZE;
37 }
比如咱们传递的 major 是 8, 那么 major_to_index 就是 8.
不难理解 ,register_blkdev() 这个函数做的事情就是 , 为这 255 个指针找到归属 . 即先在 79 行调用 kmalloc 申请一个 struct blk_major_name 结构体并且让 p 指向它 , 接下来为 p 赋值 , 而 n 将指向 major_names[index], 比如 index 就是 8, 那么 n 就指向 major_names[8], 一开始它肯定为空 , 所以直接执行 94 行并进而 95 行 , 于是就把赋好值的 p 的那个结构体赋给了 major_names[8], 因此 ,major_names[8] 就既有 major 也有 name 了 ,name 就是 ”sd”.
那么此时此刻的效果是什么 ? 告诉你 , 不是在 /dev/ 目录下面有 sda,sdb 之类的文件 , 而是通过 /proc/devices 能够看到这个块设备驱动注册了 .
localhost:/usr/src/linux-2.6.22.1 # cat /proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
21 sg
29 fb
128 ptm
136 pts
162 raw
180 usb
189 usb_device
254 megaraid_sas_ioctl
Block devices:
1 ramdisk
3 ide0
7 loop
8 sd
9 md
65 sd
66 sd
67 sd
68 sd
69 sd
70 sd
71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
253 device-mapper
254 mdp