Aparar com LVM e dm-crypt

21

Tentei configurar o TRIM com o LVM e o dm-crypt no ubuntu 13.04, seguindo este tutorial:

http://blog.neutrino.es/2013/howto-properly-activate-trim-for-your-ssd-on-linux-fstrim-lvm-and-dmcrypt/

Veja as notas sobre minha configuração e meu procedimento de teste abaixo.

Questões

  1. Existe um teste confiável se o TRIM funcionar corretamente?

  2. Minha rotina de testes está errada ou o TRIM não está funcionando?

  3. Se não estiver funcionando: o que há de errado com minha configuração?

  4. Como depurar o TRIM para minha configuração e fazer com que o TRIM funcione?

Configuração

Aqui está a minha configuração:

cat /etc/crypttab

sda3_crypt UUID=[...] none luks,discard

e

cat /etc/lvm/lvm.conf

# [...]
devices  {
      # [ ... ]
      issue_discards = 1
      # [ ... ]
   }
# [...]

O SSD é um Samsung 840 Pro.

Aqui está o meu procedimento de teste

Para testar a configuração que fiz, sudo fstrim -v /resultou em

/: [...] bytes were trimmed

Fazer isso de novo resultou no /: 0 bytes were trimmedque parece fazer sentido e indicou que o TRIM parece funcionar.

No entanto, então eu fiz este teste:

dd if=/dev/urandom of=tempfile count=100 bs=512k oflag=direct

sudo hdparm --fibmap tempfile                                 

tempfile:
 filesystem blocksize 4096, begins at LBA 0; assuming 512 byte sectors.
 byte_offset  begin_LBA    end_LBA    sectors
           0    5520384    5521407       1024
      524288    5528576    5529599       1024
     1048576    5523456    5525503       2048
     2097152    5607424    5619711      12288
     8388608    5570560    5603327      32768
    25165824    5963776    5980159      16384
    33554432    6012928    6029311      16384
    41943040    6275072    6291455      16384
    50331648    6635520    6639615       4096

sync

sudo hdparm --read-sector 5520384 /dev/sda                    

/dev/sda:
reading sector 5520384: succeeded
7746 4e11 bf42 0c93 25d3 2825 19fd 8eda
bd93 8ec6 9942 bb98 ed55 87eb 53e1 01d5
c61a 3f52 19a1 0ae5 0798 c6e2 39d9 771a
b89f 3fc5 e786 9b1d 3452 d5d7 9479 a80d
114a 7528 a79f f475 57dc aeaf 25f4 998c
3dd5 b44d 23bf 77f3 0ad9 8688 6518 28ee
81db 1473 08b5 befe 8f2e 5b86 c84e c7d2
1bdd 1065 6a23 fd0f 2951 d879 e823 021b
fa84 b9c1 eadd 9154 c9f4 2ebe cd70 64ec
75a8 4d93 c8fa 3174 7277 1ffb e858 5eca
7586 8b2e 9dbc ab12 40ab eb17 8187 e67d
5e0d 0005 5867 b924 5cfd 6723 9e4a 6f5f
99a4 a3b0 eeac 454a 83b6 c528 1106 6682
ca77 4edf 2180 bf0c b175 fabb 3d4b 37e2
b834 9e3e 82f2 2fdd 2c6a c6ca 873f e71e
f979 160f 5778 356f 2aea 6176 46b6 72b9
f76e ee51 979c 326b 1436 7cfe f677 bfcd
4c3c 9e11 4747 45c1 4bb2 4137 03a1 e4c8
e9dd 43b4 a3b4 ce1b d218 4161 bf64 727b
75d8 dcc2 e14c ebec 2126 25da 0300 12bd
6b1a 28b3 824f 3911 c960 527d 97cd de1b
9f08 9a8e dcdc e65f 1875 58ca be65 82bf
e844 50b8 cc1b 7466 58b8 e708 bd3d c01f
64fb 9317 a77a e43b 671f e1fb e328 93a9
c9c7 291c 56e0 c6c1 f011 b94d 9dc7 71e6
c8b1 5720 b8c9 b1a6 14f1 7299 9122 912b
312a 0f2f a31a 8bf9 9f8c 54e6 96f3 60b8
04a7 7dc9 3caa db0a a837 e5d7 2752 b477
c22d 7598 44e1 84e9 25d4 5db5 9f19 f73b
85a0 c656 373a ec34 55fb e1fc 124e 4674
1ba8 1a84 6aa4 7cb5 455e f416 adc6 a125
c4d4 8323 4eee 2493 2920 4e38 524c 1981

sudo rm tempfile

sync

sudo fstrim /

sync

sudo hdparm --read-sector 5520384 /dev/sda

/dev/sda:
reading sector 5520384: succeeded
7746 4e11 bf42 0c93 25d3 2825 19fd 8eda
bd93 8ec6 9942 bb98 ed55 87eb 53e1 01d5
c61a 3f52 19a1 0ae5 0798 c6e2 39d9 771a
b89f 3fc5 e786 9b1d 3452 d5d7 9479 a80d
114a 7528 a79f f475 57dc aeaf 25f4 998c
3dd5 b44d 23bf 77f3 0ad9 8688 6518 28ee
81db 1473 08b5 befe 8f2e 5b86 c84e c7d2
1bdd 1065 6a23 fd0f 2951 d879 e823 021b
fa84 b9c1 eadd 9154 c9f4 2ebe cd70 64ec
75a8 4d93 c8fa 3174 7277 1ffb e858 5eca
7586 8b2e 9dbc ab12 40ab eb17 8187 e67d
5e0d 0005 5867 b924 5cfd 6723 9e4a 6f5f
99a4 a3b0 eeac 454a 83b6 c528 1106 6682
ca77 4edf 2180 bf0c b175 fabb 3d4b 37e2
b834 9e3e 82f2 2fdd 2c6a c6ca 873f e71e
f979 160f 5778 356f 2aea 6176 46b6 72b9
f76e ee51 979c 326b 1436 7cfe f677 bfcd
4c3c 9e11 4747 45c1 4bb2 4137 03a1 e4c8
e9dd 43b4 a3b4 ce1b d218 4161 bf64 727b
75d8 dcc2 e14c ebec 2126 25da 0300 12bd
6b1a 28b3 824f 3911 c960 527d 97cd de1b
9f08 9a8e dcdc e65f 1875 58ca be65 82bf
e844 50b8 cc1b 7466 58b8 e708 bd3d c01f
64fb 9317 a77a e43b 671f e1fb e328 93a9
c9c7 291c 56e0 c6c1 f011 b94d 9dc7 71e6
c8b1 5720 b8c9 b1a6 14f1 7299 9122 912b
312a 0f2f a31a 8bf9 9f8c 54e6 96f3 60b8
04a7 7dc9 3caa db0a a837 e5d7 2752 b477
c22d 7598 44e1 84e9 25d4 5db5 9f19 f73b
85a0 c656 373a ec34 55fb e1fc 124e 4674
1ba8 1a84 6aa4 7cb5 455e f416 adc6 a125
c4d4 8323 4eee 2493 2920 4e38 524c 1981

Isso parece indicar que o TRIM não funciona. Desde a

sudo hdparm -I /dev/sda | grep -i TRIM                        
       *    Data Set Management TRIM supported (limit 8 blocks)
       *    Deterministic read ZEROs after TRIM

Editar

Aqui está a saída de sudo dmsetup table

lubuntu--vg-root: 0 465903616 linear 252:0 2048
lubuntu--vg-swap_1: 0 33308672 linear 252:0 465905664
sda3_crypt: 0 499222528 crypt aes-xts-plain64 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0 8:3 4096 1 allow_discards

Aqui está o meu /etc/fstab:

# <file system> <mount point>   <type>  <options>       <dump>  <pass>
/dev/mapper/lubuntu--vg-root /               ext4    errors=remount-ro 0       1
# /boot was on /dev/sda2 during installation
UUID=f700d855-96d0-495e-a480-81f52b965bda /boot           ext2    defaults        0       2
# /boot/efi was on /dev/sda1 during installation
UUID=2296-2E49  /boot/efi       vfat    defaults        0       1
/dev/mapper/lubuntu--vg-swap_1 none            swap    sw              0       0
# tmp
tmpfs /tmp tmpfs nodev,nosuid,noexec,mode=1777          0       0 

Editar:

Finalmente, relatei isso como um bug em https://bugs.launchpad.net/ubuntu/+source/lvm2/+bug/1213631

Espero que alguém encontre uma solução lá ou, pelo menos, teste a instalação e verifique o bug.

Atualizar

Agora funciona, veja a resposta aceita.

aluna
fonte
Parece que o LVM está faltando descartes, issue_discardsnão deveria ser issue discardsse isso não fosse um erro de digitação. allow_discardsdeve aparecer na tabela dmsetup para as partições LVM.
Frostschutz
Desculpe, este foi um erro de digitação. Eu tenho issue_discards = 1no meu arquivo de configuração.
student
Se eu fosse você, tentaria usar um destino iSCSI e testá-lo via tcpdump / wireshark para verificar se a instalação funciona, embora eu não saiba se o destino iSCSI do Linux suporta ou não o corte. Eu acredito que o dm-crypt não deve apagar os blocos no disco físico, porque isso facilita ignorar o espaço livre no dispositivo ao tentar forçá-lo com força bruta (embora não saiba se faz isso ou não, ) Além disso, os SSDs não precisam retornar zeros após o apagamento, pois o nível de desgaste pode redirecionar a leitura para um bloco diferente do que o apagado.
quer
1
De acordo com bugzilla.redhat.com/show_bug.cgi?id=958096 eu entendi mal o issue_discards = 1.
frostschutz

Respostas:

23

Eu sugiro usar um método de teste diferente. hdparmé um pouco estranho, pois fornece endereços de dispositivo em vez de endereços de sistema de arquivos, e não diz a qual dispositivo esses endereços se relacionam (por exemplo, resolve partições, mas não os destinos do dispositivo, etc.). Muito mais fácil de usar algo que adere aos endereços do sistema de arquivos, dessa forma é consistente (talvez exceto para sistemas de arquivos não tradicionais como zfs / btrfs).

Crie um arquivo de teste: (não aleatório de propósito)

# yes | dd iflag=fullblock bs=1M count=1 of=trim.test 

Obter o endereço, comprimento e tamanho do bloco: (o comando exato depende da filefragversão)

# filefrag -s -v trim.test
File size of trim.test is 1048576 (256 blocks, blocksize 4096)
 ext logical physical expected length flags
   0       0    34048             256 eof
trim.test: 1 extent found

Obtenha o dispositivo e o ponto de montagem:

# df trim.test
/dev/mapper/something  32896880 11722824  20838512   37% /mount/point

Com essa configuração, você tem um arquivo trim.testpreenchido com yes-pattern /dev/mapper/somethingno endereço 34048com comprimento de 256blocos de 4096bytes.

A leitura direta do dispositivo deve produzir o yespadrão:

# dd bs=4096 skip=34048 count=256 if=/dev/mapper/something | hexdump -C
00000000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*
00100000

Se TRIM estiver ativado, esse padrão deverá mudar quando você excluir o arquivo. Observe que os caches também precisam ser eliminados, caso contrário dd, não relerão os dados do disco.

# rm trim.test
# sync
# fstrim -v /mount/point/ # when not using 'discard' mount option
# echo 1 > /proc/sys/vm/drop_caches
# dd bs=4096 skip=34048 count=256 if=/dev/mapper/something | hexdump -C

Na maioria dos SSD, isso resultaria em um padrão zero:

00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00100000

Se a criptografia estiver envolvida, você verá um padrão aleatório:

00000000  1f c9 55 7d 07 15 00 d1  4a 1c 41 1a 43 84 15 c0  |..U}....J.A.C...|
00000010  24 35 37 fe 05 f7 43 93  1e f4 3c cc d8 83 44 ad  |$57...C...<...D.|
00000020  46 80 c2 26 13 06 dc 20  7e 22 e4 94 21 7c 8b 2c  |F..&... ~"..!|.,|

Isso ocorre porque, fisicamente aparada, a camada de criptografia lê zeros e descriptografa esses zeros para dados "aleatórios".

Se o yespadrão persistir, provavelmente nenhum corte foi feito.

frostschutz
fonte
1
@ aluno: Eu me sinto mal por não ter percebido isso anteriormente, editei a resposta para descartar caches antes hexdump.
Frostschutz 28/09
1
Obrigado, esse foi o ponto que faltava. Agora parece funcionar!
student
2
Ainda não tenho certeza se o kernel não deve soltar caches sozinho sempre que apara algo em um SSD. Os caches não devem retornar dados incorretos. Também é um desperdício de memória cache, se ocupado por algo que não está mais lá ... tudo bem.
Frostschutz 29/09/2013
1
@frostschutz Obrigado por esta ótima solução. Eu criei um script para automatizar o processo se alguma pessoa preguiçosa vier aqui.
Des
1
Recém-chegados , observe que o comando TRIM nem sempre "zera" os blocos imediatamente. Veja aqui , aqui e aqui . Embora deva, no caso do OP, já que o hdparm -Iresultado indica "Deterministic ler ZEROs after TRIM".
precisa saber é o seguinte
3

Sua rotina de teste está errada - você está obtendo números de setor em relação ao dispositivo de bloco no qual o sistema de arquivos fica - que, neste caso, é um volume lógico. O volume lógico, é claro, não inicia no primeiro setor do volume físico (e pode nem ser contíguo).

Mesmo que o volume lógico tenha iniciado no setor 0 do volume físico (o que não ocorre), o volume físico é na verdade outro destino de mapeador de dispositivo, este para criptografia. E provavelmente existe um cabeçalho LUKS na frente, para que os números do setor também não correspondam.

Se você deseja trabalhar com o mapeamento do número do setor no disco subjacente, dmsetup tablesfornecerá as informações necessárias. Se você colar aqui, verifique se a sua é uma versão que não mostra a chave na saída (ela deve mostrar todos os 0s)! (Não há recuperação de divulgar a chave - ela não pode ser alterada - é muito pior do que divulgar a senha).

Sugiro que, para depurar (depois de elaborar o mapeamento do setor), você comece no nível mais baixo e confirme que funciona lá. APARECE um sistema de arquivos diretamente em / dev / sdaX e certifique-se de que funcione (é bem possível que o dispositivo esteja, e o trim não leia zeros novamente). Em seguida, dm-crypt em cima disso, apare um sistema de arquivos e verifique se ele funciona. Por fim, coloque o LVM no topo e verifique se funciona.

derobert
fonte
@ aluno OK, esse é o setor errado então (os dois primeiros parágrafos da minha resposta). Editarei minha resposta para remover essa frase sobre o setor 6575104, pois ela não é mais relevante.
derobert
Não tenho certeza de qual dispositivo devo usar dmsetup. Acabei de fazer: o sudo dmsetup table /dev/mapper/lubuntu--vg-rootque dá0 465903616 linear 252:0 2048
estudante
@student Isso significa que o setor 0 está no setor 2048 no dispositivo 252: 0. Você terá que descobrir o que é 252: 0, eu acho que é o seu dispositivo de criptografia dm (esse é o número principal e o menor, aparecerá em / dev, por exemplo). E você precisará olhar a tabela para esse dispositivo, para continuar perseguindo-o até um bloco em um dispositivo subjacente.
derobert
3

Este é apenas um script que eu gostaria de compartilhar se uma pessoa preguiçosa vier aqui. Foi feito da resposta aceita de frostschutz .

#! / bin / bash
#
# Este script é fornecido "no estado em que se encontra", sem garantia de qualquer tipo, expressa ou implícita, incluindo, entre outras, as garantias implícitas de comercialização, adequação a um fim específico ou não violação.
#
# Licença GPL2
#
# by desgua 29/04/2014

função LIMPAR {
cd "$ pasta"
[-f teste-aparar-por-desgua] && rm teste-aparar-por-desgua && echo "Arquivo temporário removido"
eco "adeus"
saída 0
}

trap 'eco; eco "Abortado". ; LIMPAR \ LIMPO; eco; saída 0 'INT HUP

if [["$ (eco $ USER)"! = "raiz"]]; então

read -n 1 -p 'Torna-se root? [S / n] 'a
    se [[$ a == "Y" || $ a == "y" || $ a == ""]]; então
        sudo $ 0 $ 1
        saída 0
    outro
        eco "
        Este script precisa de privilégios de root.
        "
        saída 1

    fi

fi


nome = $ (eco $ 0 | sed 's /.*\///')
if [$ # -ne 1]; então

eco "
Uso: $ nome / pasta / para / teste /

"
saída 1
fi

macarrão = $ 1

read -n 1 -p 'Usar fstrim? [s / N] 'a
se [[$ a == "Y" || $ a == "y"]]; então
    fs = 1
fi

method =
while [["$ method"! = "1" && "$ method"! = "2"]]; Faz
read -n 1 -s -p 'Escolha um método:
[1] hdparm (falhará no LUKS no LVM)
[2] filefrag (aviso: pode ser necessário forçar o encerramento - feche o terminal - em alguns casos de ajuste bem-sucedido se você vir uma saída que nunca termina) 
'método
feito

função SDATEST {
disco = $ (fdisk -l | grep / dev / sda)
if ["$ disk" == ""]; então
eco "
O fdisk não encontrou / dev / sda 
"
saída 1
fi
}

teste de funcionamento {
eco "Entrando /"; eco
cd $ pasta
echo "Criando o arquivo test-trim-by-desgua em $ pasta"; eco
dd se = / dev / urandom de = contagem de aparar teste por água = 10 bs = 512k
eco "Sincronizando e dormindo 2 segundos." ; eco
sincronizar
dormir 2

hdparm --fibmap test-trim-by-desgua
lbab = $ (hdparm --fibmap teste-aparar-por-desgua | tail -n1 | awk '{print $ 2}')

eco "Como você pode ver, o arquivo foi criado e seu LBA começa em $ lbab"; eco

eco "Sincronizando e dormindo 2 segundos." ; eco
sincronizar
dormir 2

echo "Removendo arquivo test-trim-by-desgua"; eco
rm test-trim-by-desgua

trap 'eco; eco; eco "Abortado". ; eco; saída 0 'INT
eco "Sincronizando e dormindo 2 segundos." ; eco
sincronizar
dormir 2

if [["$ fs" == "1"]]; então
    eco "fstrim $ pasta && sleep 2"; eco
    fstrim $ pasta
    dormir 2
fi

echo "Isso é lido no setor $ lbab:"
hdparm --read-sector $ lbab / dev / sda

pass = $ (hdparm - setor de leitura $ lbab / dev / sda | grep "0000 0000 0000 0000")

if [[$ pass == ""]]; então
    eco "
Falha no corte ... 
Você verá apenas 0000 0000 0000 0000 ...
"
outro
    eco "Sucesso !!!"
fi
saída 0

}

função LUKSTEST {
# Referência: /unix/85865/trim-with-lvm-and-dm-crypt#
eco 1> / proc / sys / vm / drop_caches
cd $ pasta
eco "Criando um arquivo \" yes \ "."
sim dd iflag = fullblock bs = contagem de 1M = 1 de = teste-aparar-por-desgua

# position = `filefrag -s -v teste-aparar-por-desgua | grep "eof" | awk '{print $ 3}' '
position = `filefrag -s -v test-trim-by-desgua | grep "eof" | sed | || g; s |. * 255: || ; s | \. \ .. * || ''
[["$ position" == ""]] && echo "Não foi possível encontrar a posição do arquivo. Você está em um LUKS no LVM?" && LIMPAR \ LIMPO;

dispositivo = `df test-trim-by-desgua | grep "dev /" | awk '{print $ 1}' '

yes = `dd bs = 4096 skip = $ contagem de posições = 256 if = $ device | hexdump -C`

eco "Na próxima linha, você verá um padrão como: 
00000000 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a | aaaaaaaaa |
$ sim
"

if [["` echo "$ yes" | grep "aaaa" `" == ""]]; então
    eco "O padrão não pôde ser verificado. Algo deu errado. Saindo."
    LIMPAR \ LIMPO;
outro
    eco "Padrão confirmado".
fi

echo "Removendo o arquivo temporário." 
rm test-trim-by-desgua

eco "Sincronizando".
sincronizar
dormir 1

if [["$ fs" == "1"]]; então
    eco "fstrim -v $ pasta && sleep 2"; eco
    fstrim -v $ pasta
    dormir 2
fi

# Drop cache
eco 1> / proc / sys / vm / drop_caches

eco "Na próxima linha, você NÃO deve ver um padrão sim como: 
00000000 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a | aaaaaaaaa | 
Se você vir, o recorte não está funcionando:
`dd bs = 4096 skip = $ contagem de posições = 256 if = $ device | hexdump -C` "

yes = `dd bs = 4096 skip = $ contagem de posições = 256 if = $ device | hexdump -C`
if [["` echo "$ yes" | grep "aaaa" `"! = ""]]; então
    eco "TRIM não está funcionando."
outro
    eco "TRIM está funcionando!"
fi
LIMPAR \ LIMPO;
}

if [["$ method" == "1"]]; então
    SDATEST;
    TESTE;
elif [["$ method" == "2"]]; então
    LUKSTEST;
fi
saída 0

desgua
fonte