Do lado do envio ( btrfs send)

Do lado do envio ( btrfs send)

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-snapshote movies-snapshotexiste em backup. Também tentei fazer um snapshot moviespara 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-snapshotnã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-Ae music-Aexistentes 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" musicele 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 sendsaí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 -pparâmetro seja usado para especificar o "pai", btrfs sendsimplesmente 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 -ropção embtrfs subvolume snapshot -r <subvol> <snap>, emborabtrfs property set <snap> ro true/falsetambém pode ser usado para alterar o sinalizador após a criação.

btrfs sendnã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 rsynccaso 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 -pou indiretamente por meio de uma ou várias -copções:

btrfs-senddo btrfs-tools 4.13 seleciona o pai para um subvolume S e um conjunto de fontes de clones fornecidas C_iassim:

  1. se -pa opção for especificada, use-a
  2. se S não tiver parent_uuiddefinido ou este uuid não puder ser encontrado, desista
  3. se houver C_icom C_i->uuid == S->parent_uuid(cujo subvolume S é filho (instantâneo), vamos chamá-lo de "mãe"), use-o
  4. se nenhum C_i for igual parent_uuida S, desista
  5. de todos os C_i que são filhos de “mãe”, escolha aquele que tem a geração mais próxima (na verdade, ctransidqual é exatamente a diferença de “geração”?) de “mãe”.

Observe quea wikié um pouco enganador, porque sugere que -csem pé diferente de -cwith -p, embora -pgeralmente 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 -pe ignorar -c, btrfs receivesimplesmente não existe o conceito de "dois pais".

Do lado receptor ( btrfs receive)

Obtrfs-receiveA 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 sendtenha 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 snapshotsempre possui um Parent UUIDque identifica claramente seu pai e cada instantâneo criado por btrfs receivesempre possui uma Received UUIDentrada. Se foi uma transferência completa não terá nenhum Parent UUIDlançamento, se foi uma transferência incremental terá tanto um Received UUIDlançamento quanto um Parent UUIDlançamento. As entradas UUID não podem ser alteradas manualmente pelo usuário.

Esses IDs são suficientes para btrfs receiveestabelecer se possui um <parent>instantâneo do "lado receptor" quedeveser completamente idêntico ao <parent>instantâneo do "lado de envio", porque Received UUIDdeve 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/receivemas é bastante fácil de fazer manualmente, assumindo que se deseja combinar moviese musicsob um novo subvolume unifiede assumindo moviesque musictambém estão completamente espelhados no lado receptor:

  1. Crie um novo subvolume (vazio) no lado do envio:btrfs subvolume create unified
  2. Altere para somente leitura:btrfs property set unified ro true
  3. Envie para backup:btrfs send /path/to/unified | btrfs receive /receiving/side/
  4. Desativar somente leituraem ambos os lados, por exemplo, btrfs property set /path/to/unified ro falsepara o lado do envio
  5. Manualmente --reflinko conteúdo de musice moviesparaunified em ambos os lados cp -a --reflink /path/to/music /path/to/movies /path/to/unified/
  6. Definirambos os ladosos unifiedinstantâneos de volta para somente leiturabtrfs property set /path/to/unified ro true
  7. Criar um novo instantâneo de leitura e gravação unifiedpara interagir, unifiedatuará 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 musicou moviesinstantâ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 UUIDapontando 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 UUIDvalor por meio depython-btrfsdepois de ter sido desativada por btrfs-properties.

Não hábomsolução usando apenas as btrfs-progsferramentas 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 --reflinkcó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 moviese reflink a cópia musicnele:

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 sende btrfs receivedeverianã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 unifiedinstantâneo ainda está sendo transferido e, portanto, pode ser lido e gravável, então tanto o unifiedsubvolume do lado de envio quanto o instantâneo do lado de recebimento devem ser idênticos e mesclamos os subvolumes com sucesso.

informação relacionada