`
javatome
  • 浏览: 829959 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Linux那些事儿之我是U盘(35)彼岸花的传说(三)

 
阅读更多

遥想公瑾当年,小乔出嫁了,雄姿英发.

羽扇纶巾,谈笑间,樯橹灰飞烟灭.

故国神游,多情应笑我,早生华发,

人生如梦,一樽还酹江月.

的确,人生如梦,设计Linux代码的人想必非常认可这种观点,因为他们已然把这种思想融入到了代码中去,所以在代码里我们常看到睡眠,唤醒,睡眠,唤醒...而作为当年的大学生,Linus想必也很认同大学生活的现状,即大学生活就是睡觉,只是有的人两个人睡,有的人一个人睡.

前面已经说了,父进程在函数usb_stor_acquire_resources()里边,810,wait_for_completion(&(us->notify)),进入睡眠,而刚才咱们在子进程里已经看到,complete(&(us->notify))被调用,于是父进程被唤醒,回到usb_stor_acquire_resources()函数中,往下走,812,无它,唯返回耳.返回了0.于是咱们终于回到了storage_probe()函数中来.

1001,scsi_add_host()函数被执行,之前申请的us->host被作为参数传递给她,同时,intf->dev也被传递给她,这个冬冬是被用来注册sysfs.scsi_host_alloc之后,必须执行scsi_add_host(),这样,scsi核心层才能够知道有这么一个host存在.scsi_add_host()成功则返回0,否则返回出错代码.如果一切顺利,咱们将走到1009,又一次见到了kernel_thread,不需要更多解释,这里自然还是创建一个内核守护进程,只不过这次是usb_stor_scan_thread,而上次是usb_stor_control_thread.usb_stor_scan_thread()函数也是定义于drivers/usb/storage/usb.c:

886 /* Thread to carry out delayed SCSI-device scanning */
887 static int usb_stor_scan_thread(void * __us)
888 {
889 struct us_data *us = (struct us_data *)__us;
890
891 /*
892 * This thread doesn't need any user-level access,
893 * so get rid of all our resources.
894 */
895 lock_kernel();
896 daemonize("usb-stor-scan");
897 unlock_kernel();
898
899 printk(KERN_DEBUG
900 "usb-storage: device found at %d/n", us->pusb_dev->devnum);
901
902 /* Wait for the timeout to expire or for a disconnect */
903 if (delay_use > 0) {
904 printk(KERN_DEBUG "usb-storage: waiting for device "
905 "to settle before scanning/n");
906 retry:
907 wait_event_interruptible_timeout(us->scsi_scan_wait,
908 test_bit(US_FLIDX_DISCONNECTING, &us->flags),
909 delay_use * HZ);
910 if (current->flags & PF_FREEZE) {
911 refrigerator(PF_FREEZE);
912 goto retry;
913 }
914 }
915
916 /* If the device is still connected, perform the scanning */
917 if (!test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
918 scsi_scan_host(us->host);
919 printk(KERN_DEBUG "usb-storage: device scan complete/n");
920 }
921
922 complete_and_exit(&us->scsi_scan_done, 0);
923 }
显而易见,这里的daemonize()又会让咱们再ps -el的命令输出中看到有usb-stor-scan这么一个精灵进程.

903,delay_use哪来的?同一文件中,最开始的地方,定义了一个静态变量,

101 static unsigned int delay_use = 5;
102 module_param(delay_use, uint, S_IRUGO | S_IWUSR);
103 MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");

设置了delay_use5,module_paramLK 2.6提供的一个宏,使得delay_use可以在模块被装载的时候设定.(如果不设,那么她自然就是这里的值5,表示使用一个新的设备之前等待5秒延时.)为啥要delay?不为啥,只是因为天上的星星会流泪,地上的玫瑰会枯萎.您插进去的u盘也可能立刻又被您拔出来了,试想您插入以后一两秒之内又拔出来,那么咱们下面也不用耽误工夫再检测了嘛不是.

903,判断delay_use>0,然后907,wait_event_interruptible_timeout(),它的第一个参数是us->scsi_scan_wait,请回答,us->scsi_scan_wait是第一次露面吗?

混迹外企这么多日子, 我可以很负责任的很有诚意的用英语语重心长的告诉你: The answer is no. storage_probe()函数的最初,us的初始化时,scsi_scan_wait被初始化了.947,init_waitqueue_head(&us->scsi_scan_wait),而在定义struct us_data,有一个成员就是scsi_scan_wait,wait_queue_head_t scsi_scan_wait,这些都是什么意思呢?

实际上wait_event_interruptible_timeout()是一个宏,它代表着Linux中的一种等待机制,等待某个事件的发生,函数原型中,第一个参数是一个等待队列头,wait_queue_head_t定义的变量,LK 2.6中使用init_waitqueue_head()函数初始化这个等待队列,然后第三个参数是设置超时,比如咱们这里设了5s,这表示如果5秒到了,那么函数会返回0,不管其它条件如何.第二个参数是一种等待的条件,或者说等待的事件,如果条件满足了,那么函数也会返回,条件要是不满足,那么这个进程会进入睡眠,不过interruptible表明了信号可以把她中断.一旦进入睡眠,那么有三种情况,一种是wake_up或者wake_up_interruptible函数被另一个进程执行,从而唤醒她,第二种是信号中断她,第三种就是刚才讲的超时,时间到了,自然就会返回.

那么这里具体来说,先判断US_FLIDX_DISCONNECTING这个flag有没有设,如果没有设才进入睡眠,否则就不需要浪费彼此的感情了.在进入睡眠之后,如果5秒之内您没有把u盘拔出来,那么5秒一到,函数返回0,继续往下走,如果您在5秒之前拔出来了,那么后来咱们会讲,storage_disconnect()函数会执行,她会设置US_FLIDX_DISCONNECTING这个flag,并且她会调用wake_up(&us->scsi_scan_wait)来唤醒这里睡眠的进程,告诉他:"别等了,哥们儿,你没那种命!"这样函数就会提前返回,不用等到5秒再返回了.总之不管条件满不满足,5秒之内肯定会返回,所以我们继续往下看.

910,看到PF_FREEZE这个标记,有点眼熟,不过上次咱们看到的是PF_NOFREEZE,这些都是电源管理的内容,无需理会.对于usb设备,它可以进入suspend状态,那么如果设置了这个flag,这里就让它进入吧,于是有人问了,这个flag我们从没设过啊,问题是这个flag不一定非得是我们来设,要知道这里可能等待了一段时间的,(delay_use),既然等待了一段时间,就有可能被认为是要进入睡眠,总线上就不会有活动,于是上头以为每人要理睬这个usb设备了,于是就会为它设置进入suspendflag.特别的情况,你小子吃错药了没事做,delay_use给设成1光年,什么?光年不是时间单位?那好吧,那假设你把delay_use设成杨过喜欢的十六年,那你说这个设备是不是该进入suspend状态?或者说是不是该进入休眠状态?如果是,那么调用内核提供的函数, refrigerator()去休眠.

917,再次判断设备有没有被断开,如果还是没有,那么执行scsi_scan_host()函数扫描,扫描然后就知道这个host或者说这个scsi卡上面接了什么设备(虽然咱们这个只是模拟的scsi),然后cat /proc/scsi/scsi才能看到您的u盘嘛不是.(scsi_scan_host()这里面发生了很多很多的故事,但这都是scsi那层的故事,咱们暂时先不去关注好不?)

然后922,complete_and_exit函数,她和complete函数还有一点点不一样,除了唤醒别人,还得结束自己(exit).她的户口在kernel/exit.c:

842 NORET_TYPE void complete_and_exit(struct completion *comp, long code)
843 {
844 if (comp)
845 complete(comp);
846
847 do_exit(code);
848 }
所以这里会先检查&us->scsi_scan_done,struct us_data,定义了一个成员struct completion scsi_scan_done,而在storage_probe()函数一开始为us进行初始化的时候,调用了init_completion(&us->scsi_scan_done)us->scsi_scan_done进行了初始化,如果此前storage_disconnect()函数被调用了,那么她会调用wait_for_completion(&us->scsi_scan_done)来进入睡眠并且等待咱们这里把她唤醒,此乃后话,暂且不表.待到分析storage_disconnect的时刻再来揭晓.但是如果根本就没有人调用wait_for_completion(&scsi_scan_done),那么也就是说没有人睡眠,那么这个complete函数就什么也不做.然后do_exit()函数不用多说,内核提供的函数,结束进程.也就是说,对于上面这个scan的精灵进程,到这里她就会结束退出了.可以看出它是一个短命的守护进程,真的不知该说天妒英才又还是该说红颜命薄呢.总之对于这个精灵进程来说,她的使命就是让你能在cat /proc/scsi/scsi中看到你的U,当然了,从此以后你在/dev目录下面也就能看到你的设备了,比如/dev/sda.

再来看父进程,也就是storage_probe(),在用kernel_thread()创建了usb_stor_scan_thread之后,一切正常的话,storage_probe()也走到了尽头了.1017,return 0.终于,这个不老的传说也终于到了老的那一刻,一切都结束了,一切都烟消云散了.在这世上所有的事情都必须有个结束.--席慕蓉

分享到:
评论

相关推荐

    Linux那些事儿之我是U盘

    Linux那些事儿之我是U盘

    Linux那些事儿之我是U盘.pdf

    Linux那些事儿之我是U盘-有书签版.pdf

    Linux那些事儿

    Linux那些事儿之我是U盘 Linux那些事儿之我是Hub Linux那些事儿之我是USB Core Linux那些事儿之我是UHCI Linux那些事儿之我是EHCI控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是...

    Linux那些事儿1-9合集

    读过《linux那些事儿之我是U盘》的人,都知道其风格,我就不多说了。 导读: linux那些事儿之我是U盘 linux那些事儿之我是HUB linux那些事儿之我是USB Core linux那些事儿之我是UHCI Linux那些事儿之我是EHCI主机控制...

    Linux那些事儿之全集

    导读.doc Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Hub.pdf Linux那些事儿之我是USB_core.pdf Linux那些事儿之我是U盘.pdf等等 Linux那些事儿系列全在这里了

    Linux那些事儿系列.rar

    》包括《Linux那些事儿之我是Hub》、《Linux那些事儿之我是Sysfs》《Linux那些事儿之我是UHCI》、《Linux那些事儿之我是USB core》、《Linux那些事儿之我是U盘》,令人叹为观止的一个linux系列书籍。只能说,江山代...

    Linux那些事儿(linux内核写的很详细)

    Linux那些事儿 Linux那些事儿之我是Block层 Linux那些事儿之我是Sysfs Linux那些事儿之我是U盘

    Linux那些事儿之我是USB(第2版).pdf

    本书基于2.6.22内核,对USB子系统的大部分源代码逐行进行分析,系统地阐释了Linux内核中USB子系统是如何运转的,子系统内部的各个模块之间是如何互相协作、配合的。本次改版修改了第1版中出现的错误,增加了一个附录...

    Linux那些事儿之我是Hub

    Linux那些事儿之我是Hub,是前面Linux那些事之我是U盘,usb等的姐妹篇

    linux那些事儿之我是U盘

    深入浅出学linux,linux那些事儿系列之我是U盘

    linux的那些事儿全集

    Linux那些事儿之我是Block层 Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Hub Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Sysfs ...Linux那些事儿之我是U盘

    linux那些事全集

    Linux那些事儿之我是U盘 Linux那些事儿之我是USB_core Linux那些事儿之我是UHCI Linux那些事儿之我是Sysfs Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是PCI Linux那些事儿之我是Hub Linux那些事儿之我是EHCI...

    Linux那些事儿之我是XXX全集.rar

    Linux那些事儿之我是XXX全集 包含USB core U盘 UHCI PCI SCSI硬盘 Block Hub EHCI 。 想学驱动的童鞋,不妨看看。该书主要是进行源代码的分析

    Linux那些事儿 系列之2 Block+EHCI+PCI+SCSI

    Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是PCI.pdf Linux那些事儿之我是SCSI硬盘.pdf 注: 之前有人已经上传了《Linux那些事儿 系列》,其已经包含了:hub,sysfs...

Global site tag (gtag.js) - Google Analytics