多情自古伤离别,更那堪,冷落清秋节!
今宵酒醒何处?
杨柳岸,晓风残月.
此去经年,应是良辰好景虚设.
便纵有,千种风情,更与何人说?
伴随着婉约派才子,词坛浪子柳永的这首令人肝肠寸断的<<雨霖铃>>,我们来到了最后一个重要的函数,storage_disconnect.
usb设备的热插拔特性注定了我们应该在设备插入的时候做一些事情,在设备拔出的时候做一些事情.主机和usb设备的暧昧关系体现在,需要她的时候,要多缠绵有多缠绵,如胶似漆,如鱼得水.但是,有爱就有痛,有一天usb设备必定要离开主机.对于主机来说,人生没有usb设备并不会不同.而且,事实上,usb的即插即用特性也让主机知道,usb设备并不曾真的离去,他们还会再相逢.前面见面的时候调用了storage_probe来让彼此接受对方,现在就该调用storage_disconnect函数来分手.分手也许需要分财产,而usb设备离开主机也需要处理一些后事.
相比probe,disconnect函数就简单多了,造人需要辛苦30分钟,人流只要3分钟,看过杨千嬅的那部<<饺子>>之后就知道人流并不是一件麻烦事,难怪北京的街边电线杆上墙壁上到处写着无痛人流轻松搞定的广告词. storage_disconnect()函数定义在drivers/usb/storage/usb.c中,这个函数不长,
1027 /* Handle a disconnect event from the USB core */
1028 static void storage_disconnect(struct usb_interface *intf)
1029 {
1030 struct us_data *us = usb_get_intfdata(intf);
1031
1032 US_DEBUGP("storage_disconnect() called/n");
1033
1034 /* Prevent new USB transfers, stop the current command, and
1035 * interrupt a device-reset delay */
1036 set_bit(US_FLIDX_DISCONNECTING, &us->flags);
1037 usb_stor_stop_transport(us);
1038 wake_up(&us->dev_reset_wait);
1039
1040 /* Interrupt the SCSI-device-scanning thread's time delay, and
1041 * wait for the thread to finish */
1042 wake_up(&us->scsi_scan_wait);
1043 wait_for_completion(&us->scsi_scan_done);
1044
1045 /* Wait for the current command to finish, then remove the host */
1046 down(&us->dev_semaphore);
1047 up(&us->dev_semaphore);
1048 scsi_remove_host(us->host);
1049
1050 /* Wait for everything to become idle and release all our resources */
1051 usb_stor_release_resources(us);
1052 dissociate_dev(us);
1053 }
如果直到现在你还不知道1030行在干嘛,那我想问一下你他妈的是不是在耍我?虽然usb_get_intfdata()这个函数的确是第一次露面,但是这里的含义已然是司马昭之心路人皆知.usb_get_infdata()我们是没有讲过,但是我们讲过usb_set_intfdata().想当年,associate_dev()中,我们调用usb_set_intfdata(intf,us),当时我们分析了,这样做的结果就是使得%intf->dev->driver_data=us,而现在我们调用usb_get_intfdata(intf)的作用就是把us从中取出来,赋给我们这里的临时指针us.
1036行,全文中唯一一处设置US_FLIDX_DISCONNECTING这个flag的地方就在这里.
1037行, usb_stor_stop_transport(us),这个函数我们可是刚刚才讲过,你别说你就忘记了,就在command_abort()里调用的.目的就是停掉当前的urb和sg,如果有的话.
1038行, wake_up(&us->dev_reset_wait),我们也已经讲过了,就是在讲device_reset()讲到的,当时在usb_stor_reset_common()中,会使用wait_event_interruptible_timeout()来进入睡眠,睡眠的目的是给6秒钟来让设备从reset状态恢复过来,但是如果在这期间我们要断开设备了,那么当然就没有必要再让那边继续睡眠了,设备都要断开了,还有什么恢复的意义呢?所以对于这种情况,我们回过头来看usb_stor_reset_common(),会发现之后该函数立马从睡眠中醒来,然后清除掉为reset而设置的flag,US_FLIDX_RESETTING,然后就返回了,返回值是FAILED.
1042行, wake_up(&us->scsi_scan_wait),和上面这种情况几乎相同,不同的是这次唤醒的是usb_stor_scan_thread,这个函数里边也会因为delay_use的设置而调用wait_event_interrruptible_timeout去等待去睡眠,所以这里机理是一样的.而与此同时,1043行, wait_for_completion(&us->scsi_scan_done),恰恰是是等待对方的结束,我们注意到,在usb_stor_scan_thread()中最后一句话, complete_and_exit(&us->scsi_scan_done, 0),即唤醒咱们这里这个storage_disconnect()同时结束它自己.应该说这样就实现了一个同步机制.就是说因为我们之后马上要做的就是清理门户了,把一些不要的资源都释放掉,所以我们首先必须保证我们的进程都退出来,资源都不再被人使用,这样我们才可以放心的去做我们的清理工作.
1048行,scsi_remove_host()被调用,这是和最早的scsi_add_host相对应的.都是调用scsi core提供的函数.
1051行,usb_stor_release_resources(us),这个则是和我们当初那个usb_stor_acquire_resources(us)相对应.而1052行的dissociate_dev(us)则是和当初那个associate_dev()相对应.我们来看一下具体代码,来自drivers/usb/storage/usb.c,把这两个函数的代码都一并贴出来:
815 /* Release all our dynamic resources */
816 void usb_stor_release_resources(struct us_data *us)
817 {
818 US_DEBUGP("-- %s/n", __FUNCTION__);
819
820 /* Kill the control thread. The SCSI host must already have been
821 * removed so it won't try to queue any more commands.
822 */
823 if (us->pid) {
824
825 /* Wait for the thread to be idle */
826 down(&us->dev_semaphore);
827 US_DEBUGP("-- sending exit command to thread/n");
828
829 /* If the SCSI midlayer queued a final command just before
830 * scsi_remove_host() was called, us->srb might not be
831 * NULL. We can overwrite it safely, because the midlayer
832 * will not wait for the command to finish. Also the
833 * control thread will already have been awakened.
834 * That's okay, an extra up() on us->sema won't hurt.
835 *
836 * Enqueue the command, wake up the thread, and wait for
837 * notification that it has exited.
838 */
839 scsi_lock(us->host);
840 us->srb = NULL;
841 scsi_unlock(us->host);
842 up(&us->dev_semaphore);
843
844 up(&us->sema);
845 wait_for_completion(&us->notify);
846 }
847
848 /* Call the destructor routine, if it exists */
849 if (us->extra_destructor) {
850 US_DEBUGP("-- calling extra_destructor()/n");
851 us->extra_destructor(us->extra);
852 }
853
854 /* Finish the host removal sequence */
855 if (us->host)
856 scsi_host_put(us->host);
857
858 /* Free the extra data and the URB */
859 if (us->extra)
860 kfree(us->extra);
861 if (us->current_urb)
862 usb_free_urb(us->current_urb);
863
864 }
865
866 /* Dissociate from the USB device */
867 static void dissociate_dev(struct us_data *us)
868 {
869 US_DEBUGP("-- %s/n", __FUNCTION__);
870
871 /* Free the device-related DMA-mapped buffers */
872 if (us->cr)
873 usb_buffer_free(us->pusb_dev, sizeof(*us->cr), us->cr,
874 us->cr_dma);
875 if (us->iobuf)
876 usb_buffer_free(us->pusb_dev, US_IOBUF_SIZE, us->iobuf,
877 us->iobuf_dma);
878
879 /* Remove our private data from the interface */
880 usb_set_intfdata(us->pusb_intf, NULL);
881
882 /* Free the structure itself */
883 kfree(us);
884 }
823行,判断us的pid,这个pid是哪来的?很显然,usb_stor_release_resources和咱们前面说过的usb_stor_acquire_resources函数是一对,us->pid也正是来自usb_stor_acquire_resources()函数,当时在调用kernel_thread启动usb_stor_control_thread的时候,记下了kernel_thread()的返回值,并把她赋给了us->pid,实际上kernel_thread()对于父进程来说,返回值就是子进程的pid,也就是说当年创建的精灵进程的pid是被记录下来了的.写代码的人老辣的编程功底可见一斑.
840