U盘互拷的过程是什么样的?

您所在的位置:网站首页 安卓usb是什么样的 U盘互拷的过程是什么样的?

U盘互拷的过程是什么样的?

2023-04-03 06:20| 来源: 网络整理| 查看: 265

这个问题似乎很久了,题主也许已经有了答案。不过还是自作聪明答一下。

是不是应该是u盘A拷贝到内存中,内存拷贝到U盘B中。

是的

是一个dma过程,不经过cpu吗?

整个过程既有 dma,也有 cpu 参与。且 cpu 是必须参与,dma 则可有可无,只是可能会慢点。

那制约速度的是不是U盘A、B的速度和内存中缓存容量?

制约因素很多。比如[主机和 u 盘的 usb 主控,用不用 dma,文件系统的效率,cpu 速度,u 盘上的文件系统,内存中缓存大小,u 盘上的闪存芯片]等。要说清楚需要明白整个拷贝过程。

这里假设题主的问题是文件从 U 盘 A 拷贝到 U 盘 B,而不是用 U 盘 A 给 U 盘 B 制作一个镜像。

通常的 u 盘,传输过程使用的是 usb 接口,数据存储在闪存颗粒里。usb 协议只规定了串行的按字节去读的传输方式(有 4 种,有兴趣可以自行了解)。闪存芯片是一个块设备(大部分是 512 字节为单位长度),读写都是以块为单位的。所以 u 盘借助 scsi 协议(scsi 也是一种接口)来读写 u 盘里的数据。

copy/paste 时候,应用层(包括 file manager)不会关心需要拷贝的数据的存储方式,整个过程大概如下:

char *buffer = (char *) malloc(BUFFER_SIZE); int readlen = 0, writelen = 0; FILE *src = fopen("url/file", "rb"); FILE *dst = fopen("url/dstfile", "wb"); while ((readlen = fread(buffer, 1, BUFFER_SIZE, src))) { writelen = 0; while (writelen n.times { scsi_read(blocksizebuffer, 1, addr, dev); } fwrite ==> m.times { scsi_write(blocksizebuffer. 1. addr, dev); }

第一个和第三个参数很好理解,第二个参数表示读多少个块,第四个参数代表这个物理设备。第二个参数为 1 的原因呢,是因为有的(可能一些,我只粗略研究过 fat)文件系统一次只能找到一个块,读取之后才去找下一个。虽然只调用了一次文件系统的读写接口,但是会有多次对 block 层的操作。

写代码的都知道 io 是耗时操作,读写磁盘也不例外。这样一块一块的读会特别慢,尤其 scsi 协议还有准备和收尾阶段。如果一次读很多块,那准备和收尾的动作只需要做一次。按照[准备 a,读写 b,收尾 c]的耗时来计算,两种方式分别是n * (a + b + c)a + n * b + c,可以节约不少时间。其实差别比这还要大,比如第二阶段连续读可以使用 dma。

于是便有了缓存。我们一次先多读一些放在内存里,此后读内存可比读磁盘快多了。当然写也是,但是由于写时候使用缓存容易造成数据丢失,所以写缓存并不如读缓存那般被广泛使用,至少容量上要小一些。虽然加上 cache 之后每次读写都要多了检查 cache 的时间,但通常是常数级别的,比起读磁盘来九牛一毛。除去特殊情况 cache 命中率极低,那读写过程就成现在这样了:

fread ==> n.times { cached?() ? readcache() : scsi_read(rcache, rcache_size / block_size, addr, dev); } fwrite ==> whitecache(); if (wcache_need_sync()) { scsi_white(wcache, wcached_size / block_size, addr, dev); }

虽然是用 scsi 协议去规定读写方式, u 盘毕竟是 usb 设备,真正的数据还是在 usb 总线上传输的。这时候才到真正的 usb 驱动出马:

scsi_read |-- usb_bulk_transfer(); // send scsi command |-- usb_bulk_transfer(); // get data |-- usb_bulk_transfer(); // receive csw(command status wrapper) scsi_white |-- usb_bulk_transfer(); // send scsi command |-- usb_bulk_transfer(); // get data |-- usb_bulk_transfer(); // receive csw(command status wrapper)

这里每次都分了三个阶段,要弄明白这个需要自己看看 scsi 协议。为了完成传输,底层还有 usb 控制器的驱动,具体不表了。

以上过程呢,大概可以划分一下:

调用文件系统的找到真实的块地址。(CPU 工作)从 cache 里取数据给文件系统。(这个过程涉及数据拷贝,可以用 memcpy 也可以 dmacpy)如果不命中,需要从 U 盘 A 里取数据。 3.1. 主机发送 scsi command,需要一些 cpu 时间,并且数据发送过去要通过 usb 总线, usb 的速度很快(480M) 3.2. U 盘 收到 scsi command 开始准备数据,读取自己的闪存。这个过程比较耗时。 3.3. 主机准备接受设备发来的数据,这个可以和 3.2 同步进行。 3.4. 等 3.2 完成,数据从 U 盘拷贝至主机。这部分其实也分两块:通过 usb 传输,数据从 U 盘放进了电脑的 usb 主控的端点 fifo 里(480M,很快);从 fifo 拷贝到内存(可以用 dma 也可以不用,数据量大的时候 dma 要快很多)。 3.5. 主机认为数据传输完成,请求 U 盘给一个表明刚才传输状态的包。收到以后做一系列检查,此次传输完成。(主要是检查时候 CPU 耗时)将数据写入 U 盘B,经历和上述过程类似但方向相反的传输。但是写 cache 一般较小,写 flash 的速度也通常较慢,所以写入 U 盘的速度要慢于读出。(比起写入 flash 的耗时,USB 传输上下行的速度差异几乎可以忽略)


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3