首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从SCSI磁带读取时“无法分配内存”

从SCSI磁带读取时“无法分配内存”
EN

Unix & Linux用户
提问于 2017-05-19 09:51:55
回答 1查看 6.3K关注 0票数 11

我正在试验一些旧的SCSI磁带驱动器,我已经成功地将一些数据写入磁带,但我正在努力重新读取它。

代码语言:javascript
复制
# tar tvf /dev/st0
tar: /dev/st0: Cannot read: Cannot allocate memory
tar: At beginning of tape, quitting now
tar: Error is not recoverable: exiting now

# dd if=/dev/st0 of=test
dd: error reading '/dev/st0': Cannot allocate memory
0+0 records in
0+0 records out
0 bytes copied, 3.20155 s, 0.0 kB/s

在这些命令之后,dmesg说:

代码语言:javascript
复制
st 10:0:3:0: [st0] Block limits 1 - 16777215 bytes.
st 10:0:3:0: [st0] Failed to read 65536 byte block with 512 byte transfer.
st 10:0:3:0: [st0] Failed to read 131072 byte block with 65536 byte transfer.
st 10:0:3:0: [st0] Failed to read 65536 byte block with 10240 byte transfer.
st 10:0:3:0: [st0] Failed to read 94208 byte block with 69632 byte transfer.
st 10:0:3:0: [st0] Failed to read 65536 byte block with 10240 byte transfer.
st 10:0:3:0: [st0] Failed to read 65536 byte block with 512 byte transfer.

其中大部分是因为我正在用tar -b选项测试不同的块大小,但这些都没有任何效果。

偶尔,我能够从磁带上的第一个块读取几个kB数据( tar可以提取,直到数据被切断为止),但是通常在没有数据读取的情况下,它会失败。

我(显然)已经成功地将数据写入磁带,将磁带移动到另一个驱动器,查找到数据的末尾,然后写入更多的数据,因此将数据写入驱动器似乎没有什么困难,只需要再读一次。

我正在使用两个LTO-3驱动器。一个是半高HP Ultrium 920,另一个是全高HP Ultrium 960。他们俩都有这个问题。我尝试了两种不同的SCSI卡( LSI逻辑Ultra320卡和Adaptec Ultra2/SE 40 an /秒卡),它们都会产生相同的错误。

我尝试过一种带有附加终止器的电缆(即使在Ultra320卡上也给了我40 me /秒),然后是一个双连接器电缆,这意味着我只能连接一个驱动器,所以我在驱动器上启用了“术语电源”跳线,这让我连接到了Ultra160 (尽管驱动器和控制器都是Ultra320),但是所有这些都没有改变任何事情,而且在整个过程中,当我尝试从驱动器读取数据时仍然会出现相同的错误。

我将Linux内核从4.10.13降为4.4.3 (这台机器上的前一个版本),错误消息从“无法分配内存”更改为“输入/输出错误”,但问题仍然存在。

有什么想法会导致这个错误吗?

编辑:造成40 SE /秒问题是因为我使用的是SE活动终止程序。一旦我用LVD终结者取代这个,速度就上升到Ultra160。我想我需要新的电缆来访问Ultra320,但现在这是磁带带宽的两倍(最大80 me /秒),所以我暂时还好。但是,与错误消息没有任何区别。

EN

回答 1

Unix & Linux用户

回答已采纳

发布于 2017-05-20 10:21:43

好吧,我想我已经解决了。

TL;

博士

使用大块大小的dd从磁带读取:

代码语言:javascript
复制
dd if=/dev/nst0 bs=1M | tar tvf -

背景

当您写入磁带时,数据被写入称为块的单位。这些就像硬盘上的扇区。硬盘块多年来固定在512字节,直到最近才移动到4096字节块,磁带块可以设置为任意大小。

您希望使用的块大小是用setblk子命令在mt-st中设置的:

代码语言:javascript
复制
mt-st -f /dev/nst0 setblk 512    # Use 512-byte blocks
mt-st -f /dev/nst0 setblk 64k    # Use 65536-byte blocks

当您向驱动器发出读操作时,它将以块大小的块返回数据.你不能读取半个块--从磁带中读取的最小数据量是一个块,当然,根据块大小的不同,这可能是任意数量的实际字节。

这意味着,如果您使用的程序提供了一个16 be的内存缓冲区,您将能够一次从带有512字节块的磁带中读取多达32个块,这些块正好适合16 be缓冲区。但是,您将无法从带有64 at块的磁带中读取任何内容,因为您甚至不能将其中的一个放入16 at的缓冲区中,并且记住,您一次不能读取少于一个块的任何内容。

如果您试图这样做,通过使用一个块太小的缓冲区,驱动程序(在本例中是st SCSI磁带驱动程序)将返回一个内存分配错误代码,以通知您读取的缓冲区太小,甚至无法容纳单个块。

更复杂的是,一些磁带驱动器(显然是我正在使用的LTO驱动器)也支持可变大小的块。这意味着块大小是由每个写操作的大小决定,每个块可以是与最后一个块不同的大小。

设置此模式的块大小为零:

代码语言:javascript
复制
mt-st -f /dev/nst0 setblk 0    # Use variable-sized blocks

这也是默认的选项,因为--我在这里猜想--如果程序配置不正确,就会浪费更少的空间。例如,如果设置了4k块,但程序一次只以512字节的单位写入数据,那么每个512字节的数据块就有可能占用磁带上的4k。

如果你现在把所有的东西放在一起,你就会意识到磁带可以假设有一个512字节的块,然后是一个64 by的块。如果程序使用一个16 an缓冲区读取磁带,它将成功地读取第一个块,但是当它尝试读取更多数据时,它将无法在其缓冲区中容纳下面的64 an块,因此驱动程序将返回一个错误。

这就解释了为什么我大部分时间都会收到Cannot allocate memory错误,偶尔我还能得到tar来提取前几个文件,但随后又得到了错误。我没有用mt-st设置块大小,所以在编写磁带时,它默认为可变大小的块,而现在tar使用的缓冲区太小,无法读取其中的一些块。

tar有一个两种选择来设置自己的内部块大小,即--blocking-factor--read-full-records--record-size,但是只有当tar用于直接读写磁带时才能工作。

因为我通过mbuffer程序向磁带写入以减少磁带擦鞋,所以tar存档中的块大小不再匹配磁带上的块大小。这意味着--blocking-factor没有什么效果--它将允许读取磁带上的第一个块,其中包括一个标头,告诉tar阻塞因子应该是什么,其中它切换到这个值,忽略命令行上的值。这意味着第二个和以后的块不能再读取了!

溶液

解决方案是使用另一个程序从磁带中读取--一个可以将读缓冲区大小设置为足够大的值以容纳我们可能看到的最大块的程序。

dd适用于此,而在紧要关头,这种工作:

代码语言:javascript
复制
dd if=/dev/nst0 bs=256k | tar tvf -

如果磁带上有更大的块,您可能需要增加256k,但这对我有效。1M也可以正常工作,因此在合理范围内,值是否太大似乎并不重要。

票数 15
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/366039

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档