Estou explicando em breve. Tenho dois subvolumes separados para filmes e músicas, dos quais estou fazendo backup em outro disco com envio/recebimento. Gostaria de mesclar os dois subvolumes em um (com cp --reflink
) e enviá-los para a unidade de backup, clonando arquivos relinkados de instantâneos existentes.
Eu tentei criar new_volume
, depois cp -rx --reflink "music" "movies"
nele, então:
btrfs send \
-c music-snapshot \
-c movies-snapshot \
new_volume-snapshot | btrfs receive /path/to/backup
mas reclama que não é possível determinar o pai para new_volume
(identificado pelo id):
ERROR: parent determination failed for <id_number>
Claro music-snapshot
e movies-snapshot
existe em backup. Também tentei fazer um snapshot movies
para new_volume
, depois cp -rx --reflink "music"
para ele, depois um snapshot e enviar com btrfs send -c music-snapshot -p movies-snapshot new_volume-snapshot
, mas parece que -c music-snapshot
não tem efeito, os dados são enviados de qualquer maneira.
O que eu quero fazer é mesmo possível?
EDIT: Eu também tentei fazer isso:
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
Neste ponto eu tenho:
movies-A
music-A
new_volume-A (exact clone of movies-A)
Então:
cp -rx --reflink music/* new_volume/
btrfs sub snap -r new_volume new_volume-B
No final, com ambos movies-A
e music-A
existentes no destino, posso fazer:
btrfs send \
-p movies-A \
new_volume-A | btrfs receive /backup/
e isso sempre funciona perfeitamente (quase zero dados enviados). Mas...
btrfs send \
-p new_volume-A \
-c music-A \
new_volume-B | btrfs receive /backup/
Não sei explicar: com "alguns arquivos" music
ele funciona, enquanto com outros ele continua enviando dados porque estava ignorando a fonte. Acho que desta forma DEVE definitivamente funcionar, mas não consigo reproduzir de forma confiável nem o comportamento de "funcionar" nem o de "não funcionar". Estou orientado a pensar que há um bug em algum lugar. Alguém poderia tentar isso?
Responder1
(AVISO LEGAL: o comentário de lgaudino sugere que a abordagem proposta para fusão não funciona mais para btrfs-progs >=v5.14.2devido a alteraçãopropriedade btrfscomportamento ao alterar o status somente leitura de um instantâneo)
O que você deseja pode ser realizado, mas não diretamente, porque btrfs send
(e btrfs receive
) são ferramentas bastante simples,não há como "mesclar" instantâneos em um, fornecendo um pai secundáriode dentro das ferramentas.
Do lado do envio ( btrfs send
)
btrfs send
saídassistema de arquivooperações de nível (criação de diretório/arquivo, transferência de metadados, transferência de conteúdo de arquivo, etc.) que podem ser usadas no btrfs receive
"lado receptor" para criar um instantâneo equivalente em outro sistema de arquivos btrfs. Essas operações podem ser visualizadas realizando um "ensaio" viabtrfs receive --dump
.
Umincrementalsend (por exemplo, btrfs send -p <parent> <snapshot>
) funciona exatamente da mesma forma btrfs send
, exceto que apenas as operações do sistema de arquivos necessárias para criar <snapshot>
por meio de modificação (adicionar/remover diretórios/arquivos, atualizar metadados) são <parent>
registradas.
Também não há nenhuma verificação especial de relacionamento entre “pais e filhos”. Supondo que o -p
parâmetro seja usado para especificar o "pai", btrfs send
simplesmente gera os comandos necessários para passar daquele snapshot para outro (atuando como "filho"). Isso funcionaria até mesmo se os dois instantâneos não estivessem completamente relacionados.
Do lado do envio, o único requisito btrfs send
é que todos os instantâneos sejamsomente leitura. Subvolumes/instantâneos somente leitura geralmente são gerados por meio da -r
opção embtrfs subvolume snapshot -r <subvol> <snap>
, emborabtrfs property set <snap> ro true/false
também pode ser usado para alterar o sinalizador após a criação.
btrfs send
não tem consideração pelo que está ou não no lado receptor, o que é inevitável, uma vez que não há comunicação bidirecional entre os lados, como no rsync
caso de envio/recebimento de btrfs, que pode nem estar sendo executado ao mesmo tempo e, em vez disso, cada um é executado em momentos diferentes lendo/gravando em um arquivo.
Só pode haver um pai
Opágina de manuale velho)Perguntas frequentes sobre wikiinfelizmente são bastante confusos. O autor debtrfs-clone
afirmaque o envio e o recebimento de btrfs só podem, no máximo, considerarumpai para transferências incrementais. O pai pode ser especificado diretamente -p
ou indiretamente por meio de uma ou várias -c
opções:
btrfs-send
do btrfs-tools 4.13 seleciona o pai para um subvolume S e um conjunto de fontes de clones fornecidas C_iassim:
- se
-p
a opção for especificada, use-a- se S não tiver
parent_uuid
definido ou este uuid não puder ser encontrado, desista- se houver
C_i
comC_i->uuid == S->parent_uuid
(cujo subvolume S é filho (instantâneo), vamos chamá-lo de "mãe"), use-o- se nenhum C_i for igual
parent_uuid
a S, desista- de todos os C_i que são filhos de “mãe”, escolha aquele que tem a geração mais próxima (na verdade,
ctransid
qual é exatamente a diferença de “geração”?) de “mãe”.Observe quea wikié um pouco enganador, porque sugere que
-c
semp
é diferente de-c
with-p
, embora-p
geralmente esteja implícito no algoritmo acima. A única exceção relevante é o envio de subvolumes que não possuem pai.
Em resumo, sugiro sempre especificar explicitamente um dos pais via -p
e ignorar -c
, btrfs receive
simplesmente não existe o conceito de "dois pais".
Do lado receptor ( btrfs receive
)
Obtrfs-receive
A página man descreve o propósito do programa como:
Receba um fluxo de alterações e replique um ou mais subvolumes que foram gerados anteriormente pelo btrfs send
No caso de uma transferência completa, um novo subvolume é criado; no caso de uma transferência incremental, um novo instantâneo do (equivalente do lado receptor) do <parent>
instantâneo é criado. Em ambos os casos, o subvolume/instantâneo recém-criado é inicialmenteler escrevercapaz até que o "fluxo de alterações" proveniente btrfs send
tenha sido aplicado com sucesso, então o subvolume/instantâneo é feitosomente leitura.
Obviamente, não há como implementar dois pais, já que, para começar, não há cópias copy-on-write/reflink no "fluxo de alterações". O instantâneo <parent>
simplesmente fornece a base sobre a qual o "fluxo de mudanças" é aplicado.
Mas como o lado receptor garante que seu <parent>
instantâneo seja idêntico ao <parent>
instantâneo do lado emissor? Istonunca verifica/compara o conteúdo realdos snapshots/subvolumes, mas usaUUIDmetadados relacionados com oimutabilidadesuposição para o instantâneo pai.
btrfs subvolume show <subvolume>
fornece saída como:
/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):
Cada subvolume/instantâneo possui três slots UUID, dos quais dois podem estar vazios. Cada instantâneo criado por btrfs subvolume snapshot
sempre possui um Parent UUID
que identifica claramente seu pai e cada instantâneo criado por btrfs receive
sempre possui uma Received UUID
entrada. Se foi uma transferência completa não terá nenhum Parent UUID
lançamento, se foi uma transferência incremental terá tanto um Received UUID
lançamento quanto um Parent UUID
lançamento. As entradas UUID não podem ser alteradas manualmente pelo usuário.
Esses IDs são suficientes para btrfs receive
estabelecer se possui um <parent>
instantâneo do "lado receptor" quedeveser completamente idêntico ao <parent>
instantâneo do "lado de envio", porque Received UUID
deve ser equivalente ao UUID do pai do lado de envio, garantindo assim que foi criado a partir dele, e o status somente leitura de todos os instantâneos envolvidos significa que hánão deveriahouve alguma mudança nesse meio tempo.
(Nota lateral: embora apenas um lado dos dois volumes pai contenha a entrada UUID recebida, o envio/recebimento do btrfs parece ser inteligente o suficiente para fornecer esses metadados no "fluxo de alterações", para que ambos os lados/sistemas de arquivos possam potencialmente agir como o lado "envio" ou "recebimento", com base nas necessidades do usuário)
Como mesclar dois subvolumes/instantâneos (<v5.14.2)
Como vimos, a fusão é impossível apenas, btrfs send/receive
mas é bastante fácil de fazer manualmente, assumindo que se deseja combinar movies
e music
sob um novo subvolume unified
e assumindo movies
que music
também estão completamente espelhados no lado receptor:
- Crie um novo subvolume (vazio) no lado do envio:
btrfs subvolume create unified
- Altere para somente leitura:
btrfs property set unified ro true
- Envie para backup:
btrfs send /path/to/unified | btrfs receive /receiving/side/
- Desativar somente leituraem ambos os lados, por exemplo,
btrfs property set /path/to/unified ro false
para o lado do envio - Manualmente
--reflink
o conteúdo demusic
emovies
paraunified
em ambos os ladoscp -a --reflink /path/to/music /path/to/movies /path/to/unified/
- Definirambos os ladosos
unified
instantâneos de volta para somente leiturabtrfs property set /path/to/unified ro true
- Criar um novo instantâneo de leitura e gravação
unified
para interagir,unified
atuará como pai para futuras transferências incrementais emambos os lados.
Em vez de criar um subvolume novo/vazio e enviá-lo, também seria possível começar na etapa 4 a partir de um pré-existente music
ou movies
instantâneo. Do ponto de vista do btrfs, a única coisa que importa é que os pais (futuros) dos dois lados estejam conectados através de um lado Received UUID
apontando para o outro e ambos sejam lidos apenas no momento de transferências futuras.
O que fazer para >= v5.14.2
Osolução menos ruimprovavelmente é seguir a abordagem da seção anterior, mas também redefinir manualmente o Received UUID
valor por meio depython-btrfs
depois de ter sido desativada por btrfs-properties
.
Não hábomsolução usando apenas as btrfs-progs
ferramentas padrão. A coisa mais próxima de “uma” solução pode ser explorar ofactoque o instantâneo criado durante btrfs receive
é gravável para leitura até que a transferência seja concluída e tentamos fazer nossas --reflink
cópias antes que o instantâneo seja definido como somente leitura por btrfs-receive
. Em outras palavras, explorar umcondição de corridaatualmente é a única maneira de fazer isso apenas com ferramentas padrão btrfs-progs >=5.14.2.
Obviamente, o que realmente é necessário é que alguém faça uma solicitação de recurso com o projeto btrfs para pelo menos permitir a fusão como era possível antes do 5.14.2 para pessoas que sabem o que estão fazendo.
De qualquer forma, uma exploração da condição de corrida provavelmente seria mais ou menos assim: Como ainda podemos alterar o status somente leitura de um instantâneo no lado do envio, poderíamos alterar esse instantâneo, por exemplo
use movies
e reflink a cópia music
nele:
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
Se necessário, agora podemos mover os diretórios e arquivos dentro dele unified_prep
(mas deixar o diretório de músicas em paz) e, quando estiver pronto:
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
e btrfs receive
deverianãoescolha o diretório de música adicional porque ele está presente tanto movies
(no lado do envio) quanto unified
(também no lado do cliente). Agora, IFF conseguimos fazer isso cp -a --reflink /bkp/to/music /bkp/to/unified/
no lado de recebimento (!) enquanto o novo unified
instantâneo ainda está sendo transferido e, portanto, pode ser lido e gravável, então tanto o unified
subvolume do lado de envio quanto o instantâneo do lado de recebimento devem ser idênticos e mesclamos os subvolumes com sucesso.