`
dato0123
  • 浏览: 935908 次
文章分类
社区版块
存档分类
最新评论

Linux那些事儿之我是U盘(大结局)其实世上本有路,走的人多了,也便没了路

 
阅读更多

其实信号量这东西,就像北京户口,你占了一个名额,我就可能没有了名额.但是有些事情,没有北京户口你又办不成.比如我满怀壮志的走到医院向医生表达说我希望死了以后可以捐献遗体,可得到的只是医生冷冷的回复,对不起,你没有资格,因为你没有户口.

我们前面说过,Linux,有信号量,有自旋锁,有互斥锁,自旋锁或者互斥锁从某种意义上来说就只是一种特殊的信号量,即信号量意味着资源数量有限,但这个有限也许可能比如像每年的北京户口的名额,有若干个,而锁反映的就是更加有限,限制到了数量为一,即类似于所谓的一夫一妻制.她只属于你一个人,一旦你占有了她,如果别人还要想得到她,除非你释放.或者说除非你抛弃了她.

具体到usb storage,我们不管信号量和锁在Linux中是怎么实现的,它们之间是否有区别对我们来说也无所谓,事实上,usb-storage中使用的都是锁,即便是信号量,也是把它当成锁来使用,可曾记得我们当初把信号量的初始化为1?当信号量初始化为1,那么对我们来说,它就相当于退化为一把锁了.而锁,只有两种状态,上锁和解锁.

此前我们见过很多次两组函数,但我们一直绝口不提.

她们就是scsi_lock()scsi_unlock(),以及down(&us->dev_semaphore)up(&us->dev_semaphore).

先来看第一组.她们是我们自己定义的宏.来自drivers/usb/storage/usb.h.

174 /* The scsi_lock() and scsi_unlock() macros protect the sm_state and the
175 * single queue element srb for write access */
176 #define scsi_unlock(host) spin_unlock_irq(host->host_lock)
177 #define scsi_lock(host) spin_lock_irq(host->host_lock)

显然,这两个函数就像牛郎织女一样,是一对.而她们的作用,就是利用自旋锁来保护资源,这把锁就是struct Scsi_Host的一个成员spinlock_t *host_lock.那么在什么情况下需要使用这两个自旋锁函数来保护资源呢?

当你要写us->srb的时候,(不是写us->srb的元素,而是写us->srb,比如令us->srb=NULL),这种时候,你需要使用这把自旋锁.另一种情况是,当你调用scsi mid layer(scsi中层)的函数时,有时候这些函数要求调用者拥有这把锁,host_lock.

搜索一下,发现一共有7处使用了scsi_lock.

我们列举一些来.

第一处,drivers/usb/storage/usb.c:usb_stor_release_resources()函数中,

839 scsi_lock(us->host);
840 us->srb = NULL;
841 scsi_unlock(us->host);

这个不用解释了吧,赤裸裸的写us->srb,自然要用scsi_lock/scsi_unlock.

第二处,drivers/usb/storage/transport.c:usb_stor_reset_common()函数中,

1121 scsi_lock(us->host);
1122 usb_stor_report_device_reset(us);
1123 set_bit(US_FLIDX_RESETTING, &us->flags);
1124 clear_bit(US_FLIDX_ABORTING, &us->flags);
1125 scsi_unlock(us->host);
这就是第二种情况,因为这里调用了usb_stor_report_device_reset(),这个函数来自drivers/usb/storage/scsiglue.c,也是我们定义的,

308 /* Report a driver-initiated device reset to the SCSI layer.
309 * Calling this for a SCSI-initiated reset is unnecessary but harmless.
310 * The caller must own the SCSI host lock. */
311 void usb_stor_report_device_reset(struct us_data *us)
312 {
313 int i;
314
315 scsi_report_device_reset(us->host, 0, 0);
316 if (us->flags & US_FL_SCM_MULT_TARG) {
317 for (i = 1; i < us->host->max_id; ++i)
318 scsi_report_device_reset(us->host, 0, i);
319 }
320 }

注意到,她里边调用了scsi_report_device_reset(),后者来自drivers/scsi/scsi_error.c,这正是scsi mid layer定义的函数,这个函数的注释说得很清楚,调用她时必须要拥有host lock.

有人说还有第三种情况,drivers/usb/storage/usb.c,usb_stor_control_thread()函数中,

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);

您真是太有才了,这段代码都被您注意到了.的确看起来,这里无非是调用了test_bit,但是却使用了scsi_lock/scsi_unlock这对冤家,这是什么原因?其实是这样的,我们注意到这里有两个goto语句,

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);

401,us->srb=NULL,还是老一套.这才是为什么之前要用scsi_lock的真正原因.因为我要跳转,而跳过去以后需要写us->srb,所以要获得host lock,当然我们可以把scsi_lock写在test_bit()之后,比如

321 /* has the command timed out *already* ? */
322 if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
323 us->srb->result = DID_ABORT << 16;

这里插入一行==> scsi_lock(host);
324 goto SkipForAbort;

这样改动代码也可以,显得更加严谨,不过改不改意义并不大.

当然,这一段测试超时的代码本身被使用上的可能性也不大,因为这里命令还没有开始执行呢,试想,一个命令还没有开始就超时,这种情况论几率,和中国国家男足杀进世界杯差不多吧.

再来看第二组,关于us->dev_semaphore,它更多的体现出来是一种进程间的同步机制.2.6.10的内核代码中一共有6处使用了这个信号量.分别是在device_reset(),bus_reset(),usb_stor_control_thread(),usb_stor_acquire_resources(),usb_stor_release_resources(),storage_disconnect().这几样东西之间是存在一种相互制约的关系.

比如,一种情景是,device_reset()或者bus_reset()中上了锁,所以usb_stor_control_thread()这边就不可以在这个时候执行命令,usb_stor_acquire_resources()中的GET_MAX_LUN也不能执行,因为很显然,正在reset,就好比你的电脑正在重起你当然不可能执行一个打开浏览器的操作.

而另一种情景,usb_stor_control_thread()正在执行命令,那么当然usb_stor_release_resources()函数就不能释放资源了,甚至storage_disconnect()也得等待,得等你当前这个命令执行完了,它才会去执行断开的代码.就好比你正在考场上战战兢兢的答题,老师却强行把你的试卷收上去,你说你会不会很愤怒?(当然,如果是因为你被发现,那就另当别论了.)

总之,这种关系都是相互的,相互制约,同时也保证了整个系统正常运转,如果谁违规了,那么伤害的是大家的利益.这就是Linux内核的同步机制.

好了.我的故事讲完了.蓦然回首, 发现, 其实, 我一直在寻觅, 寻觅这个故事的结局, 寻觅自己灵魂的出路, 最终, 追寻到了前者, 却一直没有找到后者.

分享到:
评论

相关推荐

    Linux那些事儿之我是U盘

    根据给定的信息,“Linux那些事儿之我是U盘”这一标题及描述主要聚焦于USB技术在Linux环境下的工作原理和技术细节。接下来,我们将基于这个主题展开深入探讨,涵盖USB技术的基本概念、USB在Linux系统中的实现机制...

    Linux那些事儿1-9合集

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

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

    ### Linux那些事儿之我是USB(第2版)关键知识点概览 #### 一、书籍概述 - **核心主题**:本书主要围绕Linux内核中的USB子系统展开,深入剖析其工作原理和技术细节。 - **目标读者**:面向Linux初学者、驱动开发者...

    LINUX\Linux那些事儿系列

    3. **Linux那些事儿之我是U盘.pdf**: USB闪存驱动器,通常称为U盘,是常见的便携式存储设备。这部分可能讲述Linux如何识别、挂载和管理U盘,包括使用ums(USB Mass Storage)驱动程序,以及如何处理文件系统的读写...

    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那些事儿之我是U盘.pdf”将关注通用串行总线(USB)闪存驱动器。这部分会解释Linux如何识别和处理USB闪存设备,包括文件系统的挂载和数据交换过程。 “Linux那些事儿之我是USB Core.pdf”涉及Linux内核的USB...

    linux那些事儿之我是USB.zip

    本压缩包文件"linux那些事儿之我是USB.zip"包含了深入理解Linux USB驱动及内核相关知识的九个文档,包括Block层、EHCI主机控制器、HUB、PCI、SCSI硬盘、Sysfs、UHCI、USB core以及U盘。这些文档旨在提供一个系统性的...

    linux那些事儿之我是U盘

    ### Linux与USB存储设备——《Linux那些事儿之我是U盘》知识点提炼 #### 引言 本文基于一篇幽默且深入的教程《Linux那些事儿之我是U盘》,该文章通过作者的亲身经历和深入浅出的讲解,介绍了Linux操作系统中USB存储...

    linux的那些事儿全集

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

Global site tag (gtag.js) - Google Analytics