Хорошо, думаю, я разобрался с этим.
Вместо этого используйте dd
с большим размером блока для чтения с ленты:
dd if=/dev/nst0 bs=1M | tar tvf -
При записи на ленты данные записываются блоками, называемыми блоками. Это как сектора на жестком диске. В то время как блоки жесткого диска были зафиксированы на уровне 512 -байт в течение многих лет и только недавно были переведены на блоки размером 4096 -байт, блоки ленты могут быть установлены любого размера, который вам нравится.
Размер блока, который вы хотите использовать, устанавливается с помощью подкоманды setblk
в mt-st
:
.
mt-st -f /dev/nst0 setblk 512 # Use 512-byte blocks
mt-st -f /dev/nst0 setblk 64k # Use 65536-byte blocks
Когда вы выполняете операцию чтения для накопителя, он возвращает данные блоками размером -. Вы не можете прочитать половину блока -наименьший объем данных, который вы можете прочитать с ленты, составляет один блок, который, конечно, может состоять из любого фактического количества байтов в зависимости от размера блока.
Это означает, что если используемая вами программа предоставляет буфер памяти размером 16 КБ, вы сможете считывать до 32 блоков за раз с ленты с блоками по 512 -байтов, поскольку они точно помещаются в буфер 16 КБ. Однако вы не сможете прочитать ничего с ленты с блоками по 64 КБ, потому что вы не можете поместить даже один из них в буфер 16 КБ, и помните, что вы не можете прочитать что-либо меньше, чем один целый блок вовремя.
Если вы попытаетесь сделать это, используя буфер, который слишком мал для одного блока, драйвер (в данном случае st
драйвер ленты SCSI )вернет код ошибки выделения памяти, чтобы сообщить вам, что ваш буфер чтения слишком мал, чтобы вместить даже один блок.
Еще больше усложняет ситуацию то, что некоторые ленточные накопители (, по-видимому, LTO, которые я использую ), также поддерживают блоки переменного -размера. Это означает, что размер блока определяется размером каждой операции записи , и размер каждого блока может отличаться от последнего.
Этот режим устанавливается с нулевым размером блока:
mt-st -f /dev/nst0 setblk 0 # Use variable-sized blocks
Это также вариант по умолчанию, так как -предположительно, здесь -я предполагаю, что он занимает меньше места при неправильно настроенной программе. Если, например, вы установили блоки размером 4 КБ, но ваша программа записывала данные только блоками по 512 байт за раз, существует риск того, что каждый блок данных размером 512 -байт займет на ленте 4 КБ.
Если вы теперь соберете все вместе, вы поймете, что лента может гипотетически иметь блок размером 512 -байт, за которым следует блок размером 64 КБ. Если программа читает ленту с буфером 16 КБ, она успешно прочитает первый блок, но затем, когда она попытается прочитать больше, она не сможет поместить следующий блок 64 КБ в свой буфер, поэтому драйвер вернет ошибка.
Это объясняет, почему большую часть времени я получал ошибки Cannot allocate memory
, и иногда мне удавалось заставить tar извлечь первые несколько файлов, но затем я снова получал ошибку. Я не установил размер блока с помощью mt-st
, поэтому по умолчанию он был установлен на блоки переменного размера -при записи на ленту, и теперь tar
использует слишком маленький буфер для чтения некоторых из этих блоков.
tar
имеет пару опций для установки собственных внутренних размеров блока, а именно --blocking-factor
, --read-full-records
и --record-size
, однако они работают, только если tar
используется для прямого чтения и записать в ленту.
Поскольку я записал на ленту через программуmbuffer
для уменьшения свечения башмака ленты -, размер блока в архиве tar
больше не соответствовал размеру блока на ленте. Это означало, что --blocking-factor
имеет мало эффекта -он позволит прочитать первый блок на ленте, который включает в себя заголовок, сообщающий tar
какой коэффициент блокировки предполагается , в котором он переключается к этому и игнорирует значение, указанное в командной строке. Это означает, что второй и последующие блоки больше не могут быть прочитаны!
Решение состоит в том, чтобы использовать другую программу для чтения с ленты -, которая может установить размер буфера чтения на значение, достаточно большое для хранения самого большого блока, который мы, вероятно, увидим.
dd
работает для этого, и в крайнем случае это работает:
dd if=/dev/nst0 bs=256k | tar tvf -
Возможно, вам придется увеличить 256k
, если на вашей ленте есть блоки большего размера, но мне это помогло. 1M
также работает нормально, поэтому не имеет значения, слишком ли велико значение в разумных пределах.