Я объясню вкратце. У меня есть два отдельных подтома для фильмов и музыки, которые я копирую на другой диск с помощью 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 send
(и btrfs 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так:
- если
-p
указана опция, используйте ее- если S не имеет
parent_uuid
набора или этот uuid не может быть найден, сдаемся- если есть
C_i
withC_i->uuid == S->parent_uuid
(подтом, в котором S является потомком (снимком), назовем его "мамой"), используйте его- если ни один C_i не имеет того же,
parent_uuid
что и S, отказаться- из всех C_i, которые являются потомками "мамы", выбрать тот, который имеет самое близкое поколение (на самом деле,
ctransid
в чем именно разница с "поколением"?) к "маме".Обратите внимание, чтовикинемного вводит в заблуждение, поскольку предполагает, что
-c
withoutp
отличается от-c
with-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 snapshot
always, имеет , Parent UUID
который четко идентифицирует его родителя, и каждый снимок, созданный btrfs receive
always, имеет 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
полностью зеркально отображены на принимающей стороне:
- Создайте новый (пустой) подтом на отправляющей стороне:
btrfs subvolume create unified
- Измените его на «только чтение»:
btrfs property set unified ro true
- Отправить в резервную копию:
btrfs send /path/to/unified | btrfs receive /receiving/side/
- Отключить только чтениес обеих сторон, например,
btrfs property set /path/to/unified ro false
для отправляющей стороны - Вручную
--reflink
содержимоеmusic
иmovies
вunified
с обеих сторонcp -a --reflink /path/to/music /path/to/movies /path/to/unified/
- Наборобе стороныснимки
unified
вернулись в режим «только для чтения»btrfs property set /path/to/unified ro true
- Создайте новый снимок для чтения и записи,
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
подтом отправляющей стороны, и его снимок принимающей стороны должны быть идентичны, и мы успешно объединили подтома.