大容量存储小工具 (MSG)

概述

大容量存储小工具(或称 MSG)充当 USB 大容量存储设备,在主机看来它是一个磁盘或 CD-ROM 驱动器。它支持多个逻辑单元 (LUN)。每个 LUN 的后端存储由普通文件或块设备提供,访问权限可以限制为只读,并且该小工具可以表明它是可移动的和/或 CD-ROM(后者意味着只读访问)。

它的要求不高;只需要一个批量输入(bulk-in)和一个批量输出(bulk-out)端点。内存需求为两个 16K 缓冲区。支持全速、高速和超高速运行。

请注意,该驱动程序在某种程度上不具备可移植性,因为它假设单个内存/DMA 缓冲区可用于批量输入和批量输出端点。对于大多数设备控制器来说,这不是问题,但可能有些控制器具有硬件限制,阻止一个缓冲区被多个端点使用。

本文档介绍了如何从用户空间使用该小工具、它与大容量存储功能(或 MSF)以及使用它的不同小工具之间的关系,以及它与文件存储小工具(或 FSG,不再包含在 Linux 中)的区别。本文将简要讨论如何在复合小工具中使用 MSF。

模块参数

大容量存储小工具接受以下大容量存储专用的模块参数:

  • file=filename[,filename...]

    此参数列出了用于每个逻辑单元后端存储的文件或块设备的路径。最多可以设置 FSG_MAX_LUNS (8) 个 LUN。如果指定了更多的文件,它们将被静默忽略。另请参阅 “luns” 参数。

    请注意,如果将文件用作后端存储,则不得由任何其他进程对其进行修改。这是因为主机假设数据在其不知情的情况下不会更改。它可以被读取,但(如果逻辑单元是可写的)由于主机端的缓冲,其内容可能是不确定的。

    逻辑单元的大小将被向下舍入到完整的逻辑块。对于模拟 CD-ROM 的 LUN,逻辑块大小为 2048 字节;如果后端文件是块设备,则为设备的块大小;否则为 512 字节。

  • removable=b[,b...]

    此参数指定每个逻辑单元是否应可移动。这里的 “b” 对于真可以是 “y”、“Y” 或 “1”,对于假可以是 “n”、“N” 或 “0”。

    如果为某个逻辑单元设置了此选项,小工具将接受“弹出”(eject)SCSI 请求(Start/Stop Unit)。发送该请求时,后端文件将被关闭以模拟弹出,并且在设备上的用户空间指定新的后端文件之前,主机将无法挂载该逻辑单元(参见“sysfs 条目”一节)。

    如果逻辑单元是不可移动的(默认值),则在加载模块时必须使用 “file” 参数为其指定后端文件。如果该模块是内建的,同样适用,没有例外。

    该标志的默认值为 false,但过去它是 true。这之所以改变,是为了更好地匹配文件存储小工具,而且毕竟这看起来是一个更合理的默认值。因此,为了保持与旧内核的兼容性,最好显式指定默认值。此外,如果有人依赖于旧的默认值,现在需要显式指定 “n”。

    请注意,“可移动”意味着逻辑单元的介质可以被弹出或移除(对于 CD-ROM 驱动器或读卡器而言确实如此)。它并不意味着整个小工具可以从主机上拔下;这方面的正确术语是“热插拔”。

  • cdrom=b[,b...]

    此参数指定每个逻辑单元是否应模拟 CD-ROM。默认值为 false。

  • ro=b[,b...]

    此参数指定是否应将每个逻辑单元报告为只读。这会阻止主机修改后端文件。

    请注意,如果给定逻辑单元的此标志为 false,但后端文件无法以读/写模式打开,小工具无论如何都会回退到只读模式。

    非 CD-ROM 逻辑单元的默认值为 false;对于模拟 CD-ROM 的逻辑单元,它被强制为 true。

  • nofua=b[,b...]

    此参数指定在发送给给定逻辑单元的 SCSI Write10 和 Write12 命令中是否应忽略 FUA 标志。

    MS Windows 默认以“删除优化模式”挂载可移动存储。对介质的所有写入都是同步的,这是通过在 SCSI Write(10,12) 命令中设置 FUA(强制单元访问)位来实现的。这会强制每次写入操作都等待数据实际写入完成,并阻止块层中的 I/O 请求聚合,从而急剧降低性能。

    请注意,这意味着如果设备由 USB 供电,并且用户在未先卸载设备的情况下拔下设备(至少某些 Windows 用户会这样做),则数据可能会丢失。

    默认值为 false。

  • luns=N

    此参数指定小工具将拥有的逻辑单元数量。它受限于 FSG_MAX_LUNS (8),更高的值将被截断。

    如果提供了此参数,并且 “file” 参数中指定的文件数大于 “luns” 的值,则所有多余的文件都将被忽略。

    如果不存在此参数,逻辑单元的数量将根据 “file” 参数中指定的文件数推导得出。如果 file 参数也缺失,则默认假定为 1 个。

  • stall=b

    指定是否允许小工具暂停批量端点。默认值根据 USB 设备控制器的类型确定,通常为 true。

除上述内容外,该小工具还接受复合框架定义的以下参数(它们是所有复合小工具共有的,因此仅作简要列出):

  • idVendor -- USB 供应商 ID(16 位整数)

  • idProduct -- USB 产品 ID(16 位整数)

  • bcdDevice -- USB 设备版本 (BCD)(16 位整数)

  • iManufacturer -- USB 制造商字符串(字符串)

  • iProduct -- USB 产品字符串(字符串)

  • iSerialNumber -- 序列号字符串(字符串)

sysfs 条目

对于每个逻辑单元,小工具都会在 sysfs 层次结构中创建一个目录。在其中会创建以下三个文件:

  • file

    读取时,它返回给定逻辑单元的后端文件路径。如果没有后端文件(仅当逻辑单元可移动时才可能发生),则内容为空。

    写入时,它会更改给定逻辑单元的后端文件。即使未将给定逻辑单元指定为可移动,也可以执行此更改(但这在主机看来可能很奇怪)。但是,如果主机通过 Prevent-Allow Medium Removal SCSI 命令禁止了介质移除,则可能会失败。

  • ro

    反映给定逻辑单元的 ro 标志状态。可以随时读取,并且在没有为给定逻辑单元打开后端文件时可以写入。

  • nofua

    反映给定逻辑单元的 nofua 标志状态。它可以被读取和写入。

  • forced_eject

    写入时,它会导致后端文件被强制从 LUN 中拆离,而不管主机是否允许。内容无关紧要,写入任何非零字节数都会导致弹出。

    无法读取。

除此之外,像往常一样,模块参数的值可以从 /sys/module/g_mass_storage/parameters/* 文件中读取。

使用大容量存储功能的其他小工具

大容量存储小工具使用大容量存储功能来处理大容量存储协议。作为一种复合功能,MSF 也可以被其他小工具使用(例如 g_multi 和 acm_ms)。

前面各节中的所有信息对于使用 MSF 的其他小工具同样有效,但对大容量存储相关的模块参数的支持可能会缺失,或者这些参数可能会带有前缀。要弄清楚这些情况是否属实,需要查阅该小工具的文档或其源代码。

有关如何在小工具中包含大容量存储功能的示例,可以查看 mass_storage.c、acm_ms.c 和 multi.c(按复杂度排序)。

与文件存储小工具的关系

大容量存储功能以及因此的大容量存储小工具原本是基于文件存储小工具的。两者的区别在于,MSG 是一个复合小工具(即使用复合框架),而文件存储小工具是一个传统的小工具。从用户空间的角度来看,这种区别其实并不重要,但从内核黑客的角度来看,这意味着 (i) MSG 不会重复编写处理基本 USB 协议命令所需的代码,并且 (ii) MSF 可以用于任何其他复合小工具中。

正因为如此,文件存储小工具已在 Linux 3.8 中被移除。所有用户都需要过渡到大容量存储小工具。从外部来看,这两个小工具的表现大体相同,除了:

  1. 在 FSG 中,“removable” 和 “cdrom” 模块参数为所有逻辑单元设置标志,而在 MSG 中,它们接受每个逻辑单元的 y/n 值列表。如果只使用一个逻辑单元,这无关紧要,但如果有多个逻辑单元,则需要为每个逻辑单元重复输入 y/n 值。

  2. FSG 的 “serial”、“vendor”、“product” 和 “release” 模块参数在 MSG 中由复合层的参数处理,其名称分别为:“iSerialnumber”、“idVendor”、“idProduct” 和 “bcdDevice”。

  3. MSG 不支持 FSG 的测试模式,因此不支持 FSG 的 “transport”、“protocol” and “buflen” 模块参数。MSG 总是使用带有仅批量传输模式和 16 KiB 缓冲区的 SCSI 协议。