На отправляющей стороне ( btrfs send)

На отправляющей стороне ( btrfs send)

Я объясню вкратце. У меня есть два отдельных подтома для фильмов и музыки, которые я копирую на другой диск с помощью send/receive. Я хотел бы объединить два подтома в один (с помощью cp --reflink) и отправить его на резервный диск, клонируя повторно связанные файлы из существующих снимков.

Я пытался создать new_volume, затем cp -rx --reflink "music" "movies"в него, затем:

btrfs send \
    -c music-snapshot \
    -c movies-snapshot \
    new_volume-snapshot | btrfs receive /path/to/backup

но он жалуется, что не может определить родителя для new_volume(идентифицированного по идентификатору):

ERROR: parent determination failed for <id_number>

Конечно, music-snapshotи movies-snapshotсуществуют в резервной копии. Я также пробовал делать снимок moviesв new_volume, затем cp -rx --reflink "music"в него, затем делать снимок и отправлять его с btrfs send -c music-snapshot -p movies-snapshot new_volume-snapshot, но, похоже, это -c music-snapshotне имеет никакого эффекта, данные все равно отправляются.

Возможно ли вообще то, что я хочу сделать?

EDIT: Я также попытался сделать это:

btrfs sub snap -r movies movies-A
btrfs sub snap -r music music-A 
btrfs sub snap movies new_volume
btrfs sub snap -r new_volume new_volume-A

На данный момент у меня есть:

movies-A
music-A
new_volume-A (exact clone of movies-A)

Затем:

cp -rx --reflink music/* new_volume/
btrfs sub snap -r new_volume new_volume-B

В конце концов, имея в месте назначения movies-Aи music-A, я могу сделать:

btrfs send \
    -p movies-A \
    new_volume-A | btrfs receive /backup/

и это всегда отлично работает (почти ноль отправленных данных). Но...

btrfs send \
    -p new_volume-A \
    -c music-A \
    new_volume-B | btrfs receive /backup/

Не знаю, как объяснить: с "некоторыми файлами" musicработает, а с другими продолжает отправлять данные, как будто игнорируя источник. Думаю, что этот способ ДОЛЖЕН работать, но я не могу достоверно воспроизвести ни поведение "work", ни поведение "don't work". Я склонен думать, что где-то есть ошибка. Может кто-нибудь попробовать это?

решение1

(ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: комментарий lgaudino предполагает, что предложенный подход к слиянию больше не работает для btrfs-progs >=версия 5.14.2из-за изменившихсяbtrfs-свойствоповедение при изменении статуса снимка «только для чтения»)

То, что вы хотите, может быть достигнуто, но не напрямую, потому что btrfs sendbtrfs receive) являются довольно простыми инструментами,нет возможности «объединить» снимки в один, указав вторичный родительский снимокизнутри инструментов.

На отправляющей стороне ( btrfs send)

btrfs sendвыходыфайловая системаоперации уровня (создание каталога/файла, передача метаданных, передача содержимого файла и т.д.), которые могут быть использованы btrfs receiveна "принимающей стороне" для создания эквивалентного снимка на другой файловой системе btrfs. Эти операции можно увидеть, выполнив "пробный прогон" черезbtrfs receive --dump.

Анинкрементныйsend (например btrfs send -p <parent> <snapshot>) работает точно так же , за исключением того, что записываются btrfs sendтолько операции файловой системы, необходимые для создания <snapshot>путем изменения (добавление/удаление каталогов/файлов, обновление метаданных) .<parent>

Также не происходит никакой специальной проверки отношений "родитель-потомок". Предполагая, что -pпараметр используется для указания "родителя", btrfs sendпросто генерирует необходимые команды для перехода от этого снимка к другому (выступая в роли "потомка"). Это сработало бы даже в том случае, если бы два снимка были совершенно не связаны.

Единственное требование, предъявляемое к отправляющей стороне, btrfs sendзаключается в том, что все снимки должны бытьтолько для чтения. Подтома/снимки, доступные только для чтения, обычно создаются с помощью -rопции вbtrfs subvolume snapshot -r <subvol> <snap>, хотяbtrfs property set <snap> ro true/falseтакже может использоваться для изменения флага после создания.

btrfs sendне учитывает, что находится или не находится на принимающей стороне, что неизбежно, поскольку между сторонами нет двусторонней связи, например, rsyncотправка/получение Btrfs могут даже не выполняться одновременно, а вместо этого каждый из них может выполняться в разное время, считывая/записывая файл.

Родитель может быть только один.

Theстраница руководстваи (старый)Вики FAQк сожалению, довольно запутанные. Авторbtrfs-clone утверждаетчто btrfs отправляет и получает максимум может рассматриватьодинРодитель для инкрементных переводов. Родитель может быть указан либо напрямую через, -pлибо косвенно через один или несколько -cпараметров:

btrfs-sendиз btrfs-tools 4.13 выбирает родительский объект для подтома S и набора заданных источников клонирования C_iтак:

  1. если -pуказана опция, используйте ее
  2. если S не имеет parent_uuidнабора или этот uuid не может быть найден, сдаемся
  3. если есть C_iwith C_i->uuid == S->parent_uuid(подтом, в котором S является потомком (снимком), назовем его "мамой"), используйте его
  4. если ни один C_i не имеет того же, parent_uuidчто и S, отказаться
  5. из всех C_i, которые являются потомками "мамы", выбрать тот, который имеет самое близкое поколение (на самом деле, ctransidв чем именно разница с "поколением"?) к "маме".

Обратите внимание, чтовикинемного вводит в заблуждение, поскольку предполагает, что -cwithout pотличается от -cwith -p, хотя -pобычно подразумевается алгоритмом выше. Единственное соответствующее исключение — отправка подтомов, у которых нет родителя.

Подводя итог, я предлагаю всегда явно указывать одного родителя через -pи игнорировать -c, btrfs receiveпросто не имеет такого понятия, как «два родителя».

На принимающей стороне ( btrfs receive)

Thebtrfs-receiveСтраница руководства описывает назначение программы следующим образом:

Получать поток изменений и реплицировать один или несколько подтомов, которые были ранее сгенерированы btrfs send

В случае полной передачи создается новый подтом, в случае инкрементальной передачи <parent>создается новый снимок (эквивалент принимающей стороны) снимка. В любом случае, вновь созданный подтом/снимок изначальночитай пишивозможно до тех пор, пока «поток изменений», исходящий из, btrfs sendне будет успешно применен, затем создается подтом/моментальный снимоктолько для чтения.

Очевидно, что нет способа реализовать двух родителей, поскольку в "потоке изменений" изначально нет копий copy-on-write/reflink. Снимок <parent>просто предоставляет базу, на которой применяется "поток изменений".

Но как принимающая сторона может гарантировать, что ее <parent>снимок совпадает со <parent>снимком на отправляющей стороне?никогда не проверяет/сравнивает фактическое содержимоеснимков/подтомов, а скорее используетUUIDметаданные в связи снеизменностьпредположение для родительского снимка.

btrfs subvolume show <subvolume>обеспечивает вывод следующего вида:

/mnt/btrfs/subvolume
        Name:                   subvolume
        UUID:                   5e076a14-4e42-254d-ac8e-55bebea982d1
        Parent UUID:            -
        Received UUID:          -
        Creation time:          2018-01-01 12:34:56 +0000
        Subvolume ID:           79
        Generation:             2844
        Gen at creation:        2844
        Parent ID:              5
        Top level ID:           5
        Flags:                  -
        Snapshot(s):

Каждый подтом/снимок имеет три слота UUID, два из которых могут быть пустыми. Каждый снимок, созданный btrfs subvolume snapshotalways, имеет , Parent UUIDкоторый четко идентифицирует его родителя, и каждый снимок, созданный btrfs receivealways, имеет Received UUIDзапись. Если это был полный перенос, у него не будет никакой Parent UUIDзаписи, если это был инкрементный перенос, у него будут и Received UUIDзапись, и Parent UUIDзапись. Записи UUID не могут быть вручную изменены пользователем.

Эти идентификаторы достаточны для того, btrfs receiveчтобы установить, есть ли у него <parent>снимок «принимающей стороны», которыйдолженбыть полностью идентичным <parent>снимку «отправляющей стороны», поскольку он Received UUIDдолжен быть эквивалентен UUID родителя отправляющей стороны, тем самым гарантируя, что он был создан из него, а статус «только для чтения» всех задействованных снимков означает, что нетне должнапроизошли ли какие-либо изменения за это время.

(Примечание: хотя только одна сторона двух родительских томов содержит запись Received UUID, отправка/прием btrfs, похоже, достаточно умны, чтобы предоставить эти метаданные в «потоке изменений», поэтому обе стороны/файловые системы могут потенциально выступать в качестве «отправляющей» или «принимающей» стороны в зависимости от потребностей пользователя)

Как объединить два подтома/снимка (< v5.14.2)

Как мы видели, слияние невозможно с помощью только btrfs send/receive, но это довольно легко сделать вручную, предположив, что требуется объединить moviesи musicв новом подтоме unified, а также предположив, что moviesи musicполностью зеркально отображены на принимающей стороне:

  1. Создайте новый (пустой) подтом на отправляющей стороне:btrfs subvolume create unified
  2. Измените его на «только чтение»:btrfs property set unified ro true
  3. Отправить в резервную копию:btrfs send /path/to/unified | btrfs receive /receiving/side/
  4. Отключить только чтениес обеих сторон, например, btrfs property set /path/to/unified ro falseдля отправляющей стороны
  5. Вручную --reflinkсодержимое musicи moviesвunified с обеих сторон cp -a --reflink /path/to/music /path/to/movies /path/to/unified/
  6. Наборобе стороныснимки unifiedвернулись в режим «только для чтения»btrfs property set /path/to/unified ro true
  7. Создайте новый снимок для чтения и записи, unifiedс которым можно взаимодействовать, unifiedон будет выступать в качестве родительского для будущих инкрементных передач.обе стороны.

Вместо создания нового/пустого подтома и его отправки можно было бы просто начать с шага 4 с уже существующего musicили moviesмоментального снимка. С точки зрения btrfs, единственное, что имеет значение, это то, что родители двух сторон (будущие) связаны через Received UUIDуказание одной стороны на другую, и обе доступны только для чтения во время будущих передач.

Что делать для >= v5.14.2

Theнаименее плохое решениескорее всего, следует следовать подходу, описанному в предыдущем разделе, но дополнительно вручную сбросить Received UUIDзначение черезpython-btrfsпосле того, как он был снят btrfs-properties.

Здесь нетхорошийрешение, использующее только стандартные btrfs-progsинструменты. Ближайшим к решению "a" может быть использованиефактчто снимок, созданный во время, btrfs receiveдоступен для чтения и записи до тех пор, пока передача не будет завершена, и пытаемся сделать наши --reflinkкопии до того, как снимок будет установлен только для чтения btrfs-receive. Другими словами, эксплуатациясостояние гонкив настоящее время это можно сделать только с помощью стандартных инструментов btrfs-progs >=5.14.2.

Однако очевидно, что на самом деле необходимо, чтобы кто-то сделал запрос на функцию в проекте btrfs, чтобы, по крайней мере, разрешить слияние, как это было возможно до версии 5.14.2, для людей, которые знают, что делают.

В любом случае, эксплойт состояния гонки, скорее всего, будет выглядеть примерно так: поскольку мы по-прежнему можем изменить статус снимка «только для чтения» на отправляющей стороне, мы могли бы изменить указанный снимок, например:

используйте moviesи скопируйте musicв него ссылку:

btrfs property set -f movies ro false
cp -a --reflink /path/to/music /path/to/movies/
btrfs property set -f /path/to/movies ro true   
btrfs subvolume snapshot /path/to/movies /path/to/unified_prep

При необходимости теперь мы можем перемещаться по каталогам и файлам внутри них unified_prep(но оставить каталог с музыкой в ​​покое), а затем, когда все будет готово:

btrfs subvolume snapshot -r /path/to/unified_prep /path/to/unified
btrfs send -p /path/to/movies /path/to/unified | btrfs receive /path/to/backups/

btrfs sendи btrfs receiveдолженнетподхватываем дополнительный музыкальный каталог, поскольку он присутствует как на movies(отправляющей стороне), так и на unified(также клиентской стороне). Теперь, если нам удастся cp -a --reflink /bkp/to/music /bkp/to/unified/на принимающей стороне (!), пока новый unifiedснимок все еще передается и, таким образом, доступен для чтения и записи, то и unifiedподтом отправляющей стороны, и его снимок принимающей стороны должны быть идентичны, и мы успешно объединили подтома.

Связанный контент