在最新版本的Linux 内核中这段代码被修改了(用今天流行的话说就是被和谐掉了).有兴趣的同志们可以 关注一下2.6.22 版的内核. 最后的最后,补充一点,为什么scsi_host_alloc 传递进来的是一个struct scsi_host_template 指针, 而返回的确是一个struct <strong>Scsi</strong>_Host 指针?首先,这两个结构体包含很多相同的元素,但又不完全相同,它 们 协同工作,互相关联,但是各自起的作用不一样,struct <strong>Scsi</strong>_Host 结构体中有一个成员,就是一个struct scsi_host_template 指针,它就指向和它相关联的那个template,而struct scsi_host_template 中很 多个函数指针,它们的参数就是struct <strong>Scsi</strong>_Host 的指针.所以这之间的关系千丝万缕,剪不断理还乱,藕断 丝还连.一点不亚于曹禺先生的中那复杂的人物关系,唯一的差别只是这里没有乱伦关系罢了. 好了,就这些,这种复杂的关系我们不需要去完全了解,我们要做的只是知道今后我们有且仅有一个struct <strong>Scsi</strong>_Host 有且仅有一个struct scsi_host_template 就可以了. 108 至此,我们终于走到了usb_stor_acquire_resources()中第801行,即将见到这个千呼万唤始出来的 内核精灵. 彼岸花的传说(一) 彼岸花,花语是悲伤的回忆. 很久很久以前,城市的边缘开满了大片大片的曼珠沙华,它的花香有一种魔力,可以让人想起自己前世的事 情.守护曼珠沙华的是两个妖精,一个是花妖叫曼珠,一个是叶妖叫沙华.他们守侯了几千年,可是从来没有见 过面,因为开花的时候,就没有叶子,有叶子的时候没有花.他们疯狂地想念着彼此,并被这种痛苦折磨着.终 于有一天,他们决定违背神的规定偷偷地见一次面.那一年的曼珠沙华红艳艳的花被惹眼的绿色衬托着,开得 格外妖冶美丽. 曼珠和沙华受到惩罚,被打入轮回,并被诅咒永远也不能在一起,生生世世在人世间受到磨难.从那以后,蔓 珠沙华又叫彼岸花,意思是开放在天国的花,它的花的形状像一只只在向天堂祈祷的手掌,可是再也没有在这 个城市出现过.每年的秋彼岸期间(春分前后三天叫春彼岸,秋分前后三天叫秋彼岸)她会开在黄泉路上,曼珠 和沙华的每一次转世在黄泉路上闻到彼岸花的香味就能想起前世的的自己,然后发誓不分开,但只有在这一 刻,因为他们会再次跌入诅咒的轮回,灵魂籍由着这花的指引,走向幽冥…… 而为了纪念这个美丽而又忧伤的传说,Linux 内核中引入了守护进程,也正是与这个传说对应,守护进程也 叫内核精灵,当然,如果你觉得人们都太迷信,而你是共产党员,是无神论者,那么ok,你可以叫它为内核线程. 事实上我也是无神论者,不过我只敢在白天承认这一点.我们来看具体的代码. 801行,调用了kernel_thread()函数,kernel_thread(usb_stor_control_thread, us, CLONE_VM), 并将返回值用一个整型变量p 来表示,如果从前您对内核本身不是很熟悉,那这个函数就会让您有点头疼 了. 这个函数将会创建一个内核线程,而函数usb_stor_control_thread()将会执行,us 将是传递给她的参 数,CLONE_VM 只是设定的一个flag,对Linux 内核不是很熟悉的话,可以将kernel_thread 看作类似于 fork 的冬冬,什么?fork 您也不知道?好吧.不知道就不知道,只是依稀记得在那毕业求职的日子里,很多外 企 的笔试面试中都会问起fork,问一些关于她的返回值的问题,印象中,2004 年维尔软件的校园招聘笔试中考 过,后来我去Sun 中国工程研究院面试也被问起过. 实际上,简单一点说,kernel_thread()这么一执行呢, 就会有两个进程,一个是父进程,一个是子进程,子进程将会执行usb_stor_control_thread(),而us 是作 为usb_stor_control_thread 函数的参数(实参),CLONE_VM 标志表征父子进程之间共享地址空间,执 行 完usb_stor_control_thread()之后,子进程就结束了,她会调用exit()函数退出.而父进程继续顺着
usb_stor_acquire_resources()函数往下走,kernel_thread()函数对于父进程而言返回的是子进程的 进程id,所以802 行先判断,若是返回值p 小于0,则说明出错了,否则,那就把p 赋给us 的元素pid. 于是,咱们接下来必须再次兵分两路,分别跟踪父进程和子进程前进了.先看父进程,810 行,执行 wait_for_completion(&(us->notify)),如果您说wait_for_completion 是谁?您早已经把她忘怀,那么 她会很伤心的.记得咱们当初在提交urb 的时候调用过她吗?咱们初始化了一个等待队列,urb->done,然 后 咱们提交了urb,然后咱们通过调用wait_for_completion(&urb->done)进入了等待,进入了睡眠,当urb 被usb core 处理完了,或者说被urb host controller 处理完了,complete()函数将会被调用,从而唤醒咱 们那个进入睡眠的进程.所以此处也一样,us->notify 是在很早很早以前storage_probe()函数中初始化 的,该函数的945 行,init_completion(&(us->notify)),而struct us_data 中,有这么一个元素notify, 是struct completion 结构体变量,所以在这里,父进程将进入睡眠,谁来唤醒他?没错,您很聪明,正是子进 109 程,也正是在usb_stor_control_thread()函数中,会有complete(&(us->notify))这么一 句,wait_for_completion()和complete()是一对青梅竹马的函数,她们总是一起被用,一个设置进程进入 睡眠,另一个则负责把这个进入睡眠的进程唤醒,如果您知道信号量的话,她们就类似于信号量中的 down()/up()函数对,只不过她们更加安全. 好,父进程先搁一搁,反正他进入睡眠了,没人唤醒他的话,他是不会往下走的.来看子进程,也就是 usb_stor_control_thread()函数,这个函数定义于drivers/usb/storage/usb.c 中.咱们下一节再深入 这个函数,现在,休息,休息一会... 彼岸花的传说(二) 如果让观众短信投票的话,usb_stor_control_thread()这个函数中的代码无疑是整个模块中最为精华 的代码.我们只需要它中间301 行那个for(;;)就知道,这是一个死循环,即使别的代码都执行完了,即使别的 函数都退出了,这个函数仍然像永不消逝的电波一般,经典常驻.显然,只有死循环才能代码永恒.才能代表忠 诚.这是每一个守护者的职责. usb_stor_control_thread(),其代码如下: 281 static int usb_stor_control_thread(void * __us) 282 { 283 struct us_data *us = (struct us_data *)__us; 284 struct <strong>Scsi</strong>_Host *host = us->host; 285 286 lock_kernel(); 287 288 /* 289 * This thread doesn't need any user-level access, 290 * so get rid <strong>of</strong> all our resources. 291 */ 292 daemonize("usb-storage"); 293 294 current->flags |= PF_NOFREEZE; 295 296 unlock_kernel(); 297
- Page 1 and 2:
摘要 ............................
- Page 3 and 4:
迷雾重重的Bulk 传输(二)....
- Page 5 and 6:
引子 也许是在复旦养成了
- Page 7 and 8:
usb.h datafab.h dpcm.h initializers
- Page 9 and 10:
的Linux 内核划分为许许多
- Page 11 and 12:
目录下执行make 了.Ok,make 之
- Page 13 and 14:
只 是一个usb 接口.这些口
- Page 15 and 16:
中也定义了这么一些数据
- Page 17 and 18:
511 * @driver: the driver model cor
- Page 19 and 20:
233 .owner = THIS_MODULE, 234 .name
- Page 21 and 22:
91 * construct these entries. Each
- Page 23 and 24:
324 struct usb_host_config *actconf
- Page 25 and 26:
22 88 * @class_dev: driver model's
- Page 27 and 28:
必须给各个地方取名,完了
- Page 29 and 30:
26 136 trans_cmnd transport; /* tra
- Page 31 and 32:
944 init_MUTEX_LOCKED(&(us->sema));
- Page 33 and 34:
147 #if !defined(CONFIG_BLK_DEV_UB)
- Page 35 and 36:
124 #define USB_DEVICE_ID_MATCH_DEV
- Page 37 and 38:
intf 来代替. us 之所以重要,
- Page 39 and 40:
睡眠,那就得用GPF_ATOMIC,这
- Page 41 and 42:
504 if (msg >= 0 && !(unusual_dev->
- Page 43 and 44:
179 } 180 181 static struct us_unus
- Page 45 and 46:
711 /* Submitted by Hartmut Wahl */
- Page 47 and 48:
3. useProtocol 为US_SC_DEVICE, use
- Page 49 and 50:
Bus 004 Device 001: ID 0000:0000 Bu
- Page 51 and 52:
993 result = get_pipes(us); 994 if
- Page 53 and 54:
631 us->transport_reset = usb_stor_
- Page 55 and 56:
659 us->max_lun = 0; 660 break; 661
- Page 57 and 58:
740 /* Calculate and store the pipe
- Page 59 and 60: storage 会有两个bulk 端点,用
- Page 61 and 62: 比如说,复旦大学,有一个主
- Page 63 and 64: 1079 #define PIPE_ISOCHRONOUS 0 108
- Page 65 and 66: 782 us->unusual_dev->initFunction(u
- Page 67 and 68: 630 * each frame is in the fields o
- Page 69 and 70: 716 * Bulk URBs may 717 * use the U
- Page 71 and 72: 802 int number_of_packets; /* (in)
- Page 73 and 74: 先说互斥锁.它诞生于这样
- Page 75 and 76: 920 US_DEBUGP("GetMaxLUN command re
- Page 77 and 78: 148 /* set up data structures for t
- Page 79 and 80: 90 * @wValue: matches the USB wValu
- Page 81 and 82: 830 void *transfer_buffer, 831 int
- Page 83 and 84: 25 { 26 x->done = 0; 27 init_waitqu
- Page 85 and 86: 都会过期,我开始怀疑,在这
- Page 87 and 88: 是实际长度,要么就是不成
- Page 89 and 90: 87 258 行,usb_pipeendpoint,定义
- Page 91 and 92: 对爱你的人掘了一条无法
- Page 93 and 94: Type: Direct-Access ANSI SCSI revis
- Page 95 and 96: 416 /* 417 * this defines our host
- Page 97 and 98: 69 * Ioctl interface 70 * 71 * Stat
- Page 99 and 100: 155 * "is this a new device" checks
- Page 101 and 102: 241 char *proc_name; 242 243 /* 244
- Page 103 and 104: 328 * True if the low-level driver
- Page 105 and 106: 可以看到这个函数的参数
- Page 107 and 108: 451 short unsigned int max_sectors;
- Page 109: 地 说明了为啥咱们要显式
- Page 113 and 114: 341 } 342 343 /* reject if target !
- Page 115 and 116: 内核的核心位置,kernel/exit.c
- Page 117 and 118: 1023 dissociate_dev(us); 1024 retur
- Page 119 and 120: 917 行,再次判断设备有没有
- Page 121 and 122: 181 182 /* fail the command if we a
- Page 123 and 124: 83 struct timer_list eh_timeout; /*
- Page 125 and 126: 123 两个scsi_done,一个是struct
- Page 127 and 128: 56 jiffie count on our counter, the
- Page 129 and 130: 中 看到如下的定义: UNUSUAL_
- Page 131 and 132: 269 memcpy(data+16, us->unusual_dev
- Page 133 and 134: 一切准备好了之后,我们就
- Page 135 and 136: 238 (sg->offset + *offset) & (PAGE_
- Page 137 and 138: 所以对于那些不能相应INQUI
- Page 139 and 140: 239 行对unsigned int sglen 赋值
- Page 141 and 142: 请求,所以这里就判断abort
- Page 143 and 144: 112 case GPCMD_READ_HEADER: what =
- Page 145 and 146: 到北京,每每只有在夜深人
- Page 147 and 148: 580 /* 581 * If we have a failure,
- Page 149 and 150: 666 memcpy(srb->cmnd, old_cmnd, MAX
- Page 151 and 152: 950 struct bulk_cb_wrap *bcb = (str
- Page 153 and 154: 1034 /* get the status again */ 103
- Page 155 and 156: 426 /* store the actual length of t
- Page 157 and 158: 后她会给host 返回一个CSW.CB
- Page 159 and 160: 296 } 297 298 US_DEBUGP("-- transfe
- Page 161 and 162:
491 * scatter-gather or not, and ac
- Page 163 and 164:
迷雾重重的 Bulk 传输(五) us
- Page 165 and 166:
然后把她赋给了result.而us->
- Page 167 and 168:
而bcs->Status,标志命令执行
- Page 169 and 170:
就必须设置US_FL_IGNORE_RESIDUE
- Page 171 and 172:
485 }; 486 这是一个字符数组
- Page 173 and 174:
srb->sense_buffer 里边的东西.S
- Page 175 and 176:
一个类似的函数,名叫usb_sto
- Page 177 and 178:
这种命令应该由mid level 来
- Page 179 and 180:
Disk /dev/sda: 146.1 GB, 1461631057
- Page 181 and 182:
through to the most significant bit
- Page 183 and 184:
1192 USB_TYPE_CLASS | USB_RECIP_INT
- Page 185 and 186:
315 行,scsi_report_device_reset(),
- Page 187 and 188:
285 US_DEBUGP("No reset during disc
- Page 189 and 190:
229 /* Wait for the aborted command
- Page 191 and 192:
两个函数中需要判断它,一
- Page 193 and 194:
associate_dev()相对应.我们来
- Page 195 and 196:
束for 死循环,从而usb_stor_con
- Page 197 and 198:
317 for (i = 1; i < us->host->max_i