如果让观众短信投票的话,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 Scsi_Host *host = us->host;
285
286 lock_kernel();
287
288 /*
289 * This thread doesn't need any user-level access,
290 * so get rid of all our resources.
291 */
292 daemonize("usb-storage");
293
294 current->flags |= PF_NOFREEZE;
295
296 unlock_kernel();
297
298 /* signal that we've started the thread */
299 complete(&(us->notify));
300
301 for(;;) {
302 US_DEBUGP("*** thread sleeping./n");
303 if(down_interruptible(&us->sema))
304 break;
305
306 US_DEBUGP("*** thread awakened./n");
307
308 /* lock the device pointers */
309 down(&(us->dev_semaphore));
310
311 /* if us->srb is NULL, we are being asked to exit */
312 if (us->srb == NULL) {
313 US_DEBUGP("-- exit command received/n");
314 up(&(us->dev_semaphore));
315 break;
316 }
317
318 /* lock access to the state */
319 scsi_lock(host);
320
321 /* has the command timed out *already* ? */
322 if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
323 us->srb->result = DID_ABORT << 16;
324 goto SkipForAbort;
325 }
326
327 /* don't do anything if we are disconnecting */
328 if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
329 US_DEBUGP("No command during disconnect/n");
330 goto SkipForDisconnect;
331 }
332
333 scsi_unlock(host);
334
335 /* reject the command if the direction indicator
336 * is UNKNOWN
337 */
338 if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) {
339 US_DEBUGP("UNKNOWN data direction/n");
340 us->srb->result = DID_ERROR << 16;
341 }
342
343 /* reject if target != 0 or if LUN is higher than
344 * the maximum known LUN
345 */
346 else if (us->srb->device->id &&
347 !(us->flags & US_FL_SCM_MULT_TARG)) {
348 US_DEBUGP("Bad target number (%d:%d)/n",
349 us->srb->device->id, us->srb->device->lun);
350 us->srb->result = DID_BAD_TARGET << 16;
351 }
352
353 else if (us->srb->device->lun > us->max_lun) {
354 US_DEBUGP("Bad LUN (%d:%d)/n",
355 us->srb->device->id, us->srb->device->lun);
356 us->srb->result = DID_BAD_TARGET << 16;
357 }
358
359 /* Handle those devices which need us to fake
360 * their inquiry data */
361 else if ((us->srb->cmnd[0] == INQUIRY) &&
362 (us->flags & US_FL_FIX_INQUIRY)) {
363 unsigned char data_ptr[36] = {
364 0x00, 0x80, 0x02, 0x02,
365 0x1F, 0x00, 0x00, 0x00};
366
367 US_DEBUGP("Faking INQUIRY command/n");
368 fill_inquiry_response(us, data_ptr, 36);
369 us->srb->result = SAM_STAT_GOOD;
370 }
371
372 /* we've got a command, let's do it! */
373 else {
374 US_DEBUG(usb_stor_show_command(us->srb));
375 us->proto_handler(us->srb, us);
376 }
377
378 /* lock access to the state */
379 scsi_lock(host);
380
381 /* indicate that the command is done */
382 if (us->srb->result != DID_ABORT << 16) {
383 US_DEBUGP("scsi cmd done, result=0x%x/n",
384 us->srb->result);
385 us->srb->scsi_done(us->srb);
386 } else {
387 SkipForAbort:
388 US_DEBUGP("scsi command aborted/n");
389 }
390
391 /* If an abort request was received we need to signal that
392 * the abort has finished. The proper test for this is
393 * the TIMED_OUT flag, not srb->result == DID_ABORT, because
394 * a timeout/abort request might be received after all the
395 * USB processing was complete. */
396 if (test_bit(US_FLIDX_TIMED_OUT, &us->flags))
397 complete(&(us->notify));
398
399 /* finished working on this command */
400 SkipForDisconnect:
401 us->srb = NULL;
402 scsi_unlock(host);
403
404 /* unlock the device pointers */
405 up(&(us->dev_semaphore));
406 } /* for (;;) */
407
408 /* notify the exit routine that we're actually exiting now
409 *
410 * complete()/wait_for_completion() is similar to up()/down(),
411 * except that complete() is safe in the case where the structure
412 * is getting deleted in a parallel mode of execution (i.e. just
413 * after the down() -- that's necessary for the thread-shutdown
414 * case.
415 *
416 * complete_and_exit() goes even further than this -- it is safe in
417 * the case that the thread of the caller is going away (not just
418 * the structure) -- this is necessary for the module-remove case.
419 * This is important in preemption kernels, which transfer the flow
420 * of execution immediately upon a complete().
421 */
422 complete_and_exit(&(us->notify), 0);
423 }
284行,定义了一个Scsi_Host的指针host,令她指向us->host,也就是刚刚用scsi_host_alloc()申请的那个Scsi_Host结构体变量.
292行,daemonize("usb-storage"),其实,这句话才是真正创建精灵进程的,daemonize()函数来自内核的核心位置,kernel/exit.c中,她完成了这么一件事情,把一个普通的进程转换成为了精灵进程,不过此处咱们可以不去深究精灵进程的原理,甚至咱们可以认为这句话没有做任何事情,只是从此之后咱们ps命令一看能够看到有一个叫做usb-storage的进程.比如下面所看到的:
localhost:~ # ps -el
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 1 0 0 76 0 - 195 - ? 00:00:02 init
1 S 0 2 1 0 -40 - - 0 migrat ? 00:00:00 migration/0
1 S 0 3 1 0 94 19 - 0 ksofti ? 00:00:00 ksoftirqd/0
1 S 0 18 1 0 70 -5 - 0 worker ? 00:00:00 events/0
1 S 0 26 1 0 71 -5 - 0 worker ? 00:00:00 khelper
1 S 0 27 1 0 70 -5 - 0 worker ? 00:00:00 kthread
1 S 0 45 27 0 72 -5 - 0 worker ? 00:00:00 kacpid
1 S 0 229 27 0 80 0 - 0 pdflus ? 00:00:00 pdflush
1 S 0 230 27 0 75 0 - 0 pdflus ? 00:00:00 pdflush
1 S 0 231 1 0 76 0 - 0 kswapd ? 00:00:00 kswapd0
1 S 0 961 27 0 70 -5 - 0 scsi_e ? 00:00:00 scsi_eh_0
1 S 0 1033 27 0 70 -5 - 0 scsi_e ? 00:00:00 scsi_eh_1
1 S 0 1045 27 0 71 -5 - 0 scsi_e ? 00:00:00 scsi_eh_2
1 S 0 1047 27 0 70 -5 - 0 worker ? 00:00:00 scsi_wq_2
5 S 0 1262 1 0 72 -4 - 1774 - ? 00:00:02 udevd
1 S 0 1939 27 0 70 -5 - 0 hub_th ? 00:00:00 khubd
1 S 0 7804 27 0 70 -5 - 0 scsi_e ? 00:00:00 scsi_eh_3
1 S 0 7805 27 0 70 -5 - 0 - ? 00:00:00 usb-storage
4 S 0 13905 13902 0 75 0 - 2430 wait pts/1 00:00:00 bash
0 R 0 19098 13905 0 77 0 - 821 - pts/1 00:00:00 ps
显然,您在终端按ctrl-c是不可能中止这个usb-storage进程的.这是精灵进程诸多特性中的一个,她运行于后台.试一下kill -9加进程号,看你能杀死她不?(系统崩溃了我可不负责哦...)
294行,这里为目前的进程设置一个flag,PF_NOFREEZE,在整个内核代码中,这个flag也只出现过几次.这个flag是与电源管理相关的,2.6的内核为了实现与Windows相似的一个功能,Hibernate,也就是"冬眠",(别说您不知道,Windows关机选项里面有"关机","重启","注销","Stand by",以及"Hibernate").在内核编译菜单里面,Power managerment options中,有一个选项Software Suspend,也就是内核编译选项中的CONFIG_SOFTWARE_SUSPEND,选择了她使得机器可以被suspended.显然咱们不用care她.但是这里之所以要设置这个flag,是因为suspend要求把内存里的冬冬写到磁盘上,而一个进程设置了这个flag就表明它在suspend的时候不会被冻住,用行话来讲就是,they’re not refrigerated during a suspend.freeze就是冷冻,冻住的意思,过去分词frozen是形容词,冻结的,冰冻的,其实就是让进程睡眠.所以总的来说,这里的做法就是说,即使系统suspend了,这个进程,或者准确地说,这个内核线程,也不应该进入睡眠.
要执行这两个操作需要执行lock_kernel()/unlock_kernel()这一对函数.然后299行,执行complete唤醒前面那节的父进程.而子进程并不退出,她继续行走,她无怨无悔的行走,只不过余秋雨先生是为追寻人类文明足迹而进行的域外旅程,而此处子进程(执)行的她对内核的守护.她像天使一般,守护着心爱的人.
于是咱们也继续跟着她行走,299行, complete(&(us->notify)),这正是和刚才在父进程里看到的那句使进程进入睡眠的wait_for_completion(&(us->notify))相对应,这里自然是唤醒父进程,我们先继续看一下子进程,稍候马上去看父进程.
301行,一个for语句死循环,尽管外面的世界很精彩,但是咱们去看看for里面的世界也不妨.
303行,down_interruptible()函数,事实上302行的注释已经告诉咱们,thread将进入睡眠了...,也许她累了.down_interruptible的参数是&us->sema,不陌生吧,我们之前讲信号量讲互斥锁的时候就已经提过了us->sema.所以这里很简单,就是想获得这把锁,但是别忘了,我们当初就介绍过,这把锁一开始就被初始化为0了,也就是说它属于那种指腹为婚的情形,一到这个世界来就告诉别人自己已经是名花有主了.因此,这里只能进入睡眠,等待一个up()函数去释放锁.谁会调用up()函数呢?暂时先不管它,我们先关注一下父进程,毕竟我们自己进入了睡眠,而之前我们把父进程唤醒了.
分享到:
相关推荐
### Linux中的USB子系统详解——《Linux那些事儿之我是U盘》 #### 一、引言 在现代计算环境中,USB(Universal Serial Bus)已成为连接各种外围设备的标准接口之一。无论是移动存储设备如U盘,还是键盘、鼠标等输入...
Linux那些事儿之我是U盘 Linux那些事儿之我是Hub Linux那些事儿之我是USB Core Linux那些事儿之我是UHCI Linux那些事儿之我是EHCI控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是...
### Linux那些事儿之我是USB(第2版)关键知识点概览 #### 一、书籍概述 - **核心主题**:本书主要围绕Linux内核中的USB子系统展开,深入剖析其工作原理和技术细节。 - **目标读者**:面向Linux初学者、驱动开发者...
读过《linux那些事儿之我是U盘》的人,都知道其风格,我就不多说了。 导读: linux那些事儿之我是U盘 linux那些事儿之我是HUB linux那些事儿之我是USB Core linux那些事儿之我是UHCI Linux那些事儿之我是EHCI主机控制...
本压缩包文件"linux那些事儿之我是USB.zip"包含了深入理解Linux USB驱动及内核相关知识的九个文档,包括Block层、EHCI主机控制器、HUB、PCI、SCSI硬盘、Sysfs、UHCI、USB core以及U盘。这些文档旨在提供一个系统性的...
3. **Linux那些事儿之我是U盘.pdf**: USB闪存驱动器,通常称为U盘,是常见的便携式存储设备。这部分可能讲述Linux如何识别、挂载和管理U盘,包括使用ums(USB Mass Storage)驱动程序,以及如何处理文件系统的读写...
导读.doc Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Hub.pdf Linux那些事儿之我是USB_core.pdf Linux那些事儿之我是U盘.pdf等等 Linux那些事儿系列全在这里了
》包括《Linux那些事儿之我是Hub》、《Linux那些事儿之我是Sysfs》《Linux那些事儿之我是UHCI》、《Linux那些事儿之我是USB core》、《Linux那些事儿之我是U盘》,令人叹为观止的一个linux系列书籍。只能说,江山代...
“Linux那些事儿之我是U盘.pdf”将关注通用串行总线(USB)闪存驱动器。这部分会解释Linux如何识别和处理USB闪存设备,包括文件系统的挂载和数据交换过程。 “Linux那些事儿之我是USB Core.pdf”涉及Linux内核的USB...
Linux那些事儿之我是Block层 Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Hub Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Sysfs ...Linux那些事儿之我是U盘
### Linux与USB存储设备——《Linux那些事儿之我是U盘》知识点提炼 #### 引言 本文基于一篇幽默且深入的教程《Linux那些事儿之我是U盘》,该文章通过作者的亲身经历和深入浅出的讲解,介绍了Linux操作系统中USB存储...