Como posso descobrir a variedade de LBAs de um arquivo usando seu inode?

9

Ao responder a essa pergunta de U&L intitulada: Que comando eu uso para ver o bloco inicial e final de um arquivo no sistema de arquivos? , Tentei descobrir se era possível determinar o LBA de um arquivo usando seu inode.

Minha resposta determinou que eu poderia usar hdparmcomo um método para encontrar LBAs:

$ sudo hdparm --fibmap afile 

afile:
 filesystem blocksize 4096, begins at LBA 0; assuming 512 byte sectors.
 byte_offset  begin_LBA    end_LBA    sectors
           0  282439184  282439191          8

Mas fiquei curioso se havia algum método usando o inode de um arquivo para obter também os LBAs; sem usar hdparm.

Eu acho que pode haver métodos alternativos escondidos nas ferramentas filefrag, stat, debugfs, e tune2fs, mas provocá-lo está me iludindo.

Alguém pode pensar em alternativas?


Aqui estão algumas das minhas pesquisas até agora que podem ser úteis para aqueles corajosos o suficiente para tentar responder a isso.

filefrag

Suspeito que você possa usar a ferramenta filefragpara fazê-lo, especificamente usando os resultados de sua -etroca, talvez executando vários cálculos para chegar lá com os quais não estou familiarizado.

saída de amostra

$ filefrag -e afile
Filesystem type is: ef53
File size of afile is 20 (1 block of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..       0:   35304898..  35304898:      1:             eof
afile: 1 extent found

inodes

Outro método potencial que eu suspeito que possa ter potencial é usar as informações de inode de um arquivo, diretamente ou através de uma matemática complexa pouco documentada nas interwebs.

Exemplo

Primeiro descobrimos o inode do arquivo. Podemos fazer isso usando o statcomando ou ls -i.

Estado

$ stat afile 
  File: ‘afile’
  Size: 20          Blocks: 8          IO Block: 4096   regular file
Device: fd02h/64770d    Inode: 6560281     Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/    saml)   Gid: ( 1000/    saml)
Context: unconfined_u:object_r:user_home_t:s0
Access: 2013-12-27 18:40:12.788333778 -0500
Modify: 2013-12-27 18:40:23.103333073 -0500
Change: 2013-12-27 18:44:03.697317989 -0500
 Birth: -

ls -i

$ ls -i 
6560281 afile

Com as informações do inode em mãos, agora podemos abrir o sistema de arquivos em que este arquivo se encontra usando a ferramenta debugfs,.

NOTA: Para determinar o sistema de arquivos um arquivo reside em que você pode usar o comando df <filename>.

Agora, se executarmos debugfse executarmos o comando stat <inode #>, podemos obter uma lista de extensões que contêm os dados desse arquivo.

$ sudo debugfs -R "stat <6560281>" /dev/mapper/fedora_greeneggs-home
debugfs 1.42.7 (21-Jan-2013)
Inode: 6560281   Type: regular    Mode:  0664   Flags: 0x80000
Generation: 1999478298    Version: 0x00000000:00000001
User:  1000   Group:  1000   Size: 20
File ACL: 0    Directory ACL: 0
Links: 1   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x52be10c3:a640e994 -- Fri Dec 27 18:44:03 2013
 atime: 0x52be0fdc:bbf41348 -- Fri Dec 27 18:40:12 2013
 mtime: 0x52be0fe7:18a2f344 -- Fri Dec 27 18:40:23 2013
crtime: 0x52be0dd8:64394b00 -- Fri Dec 27 18:31:36 2013
Size of extra inode fields: 28
Extended attributes stored in inode body: 
  selinux = "unconfined_u:object_r:user_home_t:s0\000" (37)
EXTENTS:
(0):35304898

Agora, temos as informações de extensão acima, e é aqui que me perco e não sei como proceder.

Referências

slm
fonte

Respostas:

5

filefrage debugfsdeslocamento do relatório expresso em número de blocos do sistema de arquivos.

Para obter o deslocamento no número de unidades de 512 bytes, você precisa multiplicar pelo tamanho do bloco em unidades de 512 bytes. No ext4 FS, o tamanho do bloco costuma ser de 4k, então você precisa multiplicar por 8.

Com filefrag, você também pode usar uma -b 512opção para obter o deslocamento em unidades de 512 bytes.

Você pode obter o tamanho do bloco com o statscomando in debugfsou com o GNU stat:

stat -fc%s /mount/point

(ou qualquer arquivo nesse sistema de arquivos).

Observe que, como hdparmé um utilitário de disco rígido, ele tentará fornecer o deslocamento no disco, em oposição ao dispositivo de bloco no qual o sistema de arquivos está montado (supondo que o dispositivo de bloco resida no disco de alguma forma). Funciona apenas dessa maneira para partições (adicionando o conteúdo /sys/class/block/the-block-device/startao deslocamento real) e dispositivos md RAID 1, mas não outros tipos de dispositivos de bloco possivelmente suportados por disco, como dispositivos mapeadores de dispositivos, outros níveis de RAID, dispositivos dmraid, loop e nbd. .. Observe também que as versões anteriores hdparmdo FIBMAP ioctl são limitadas em qual dispositivo de bloco ele pode ser usado, enquanto as versões mais recentes usam o FIEMAP como filefrag.

Então, por exemplo, se você possui um ext2sistema de arquivos /dev/sda1.

# hdparm --fibmap /file/in/there
/file/in/there:
 filesystem blocksize 1024, begins at LBA 2048; assuming 512 byte sectors.
 byte_offset  begin_LBA    end_LBA    sectors
           0     109766     109767          2

Você pode obter esses dois setores (mas observe que o arquivo provavelmente usa apenas parte dele):

dd skip=109766 count=2 if=/dev/sda # not /dev/sda1

Enquanto estiver com filefragou debugfs.

# filefrag -v /file/in/there
Filesystem type is: ef53
Filesystem cylinder groups is approximately 12
File size of /file/in/there is 87 (1 block, blocksize 1024)
 ext logical physical expected length flags
   0       0    53859               1 merged,eof

Você o obtém do dispositivo de bloco real:

dd bs=1024 skip=53859 count=1 if=/dev/sda1
Stéphane Chazelas
fonte
Então, se eu entendi direito, se filefrag -b512 -v ..diz "Physical_offset: 211787168 .. 211795719", isso equivaleria aos LBAs? Isso parece aparecer com o mesmo arquivo com hdparm --fibmap211787168..211795719. Se eu largar o -b512 -ve usar o def. 1024 e tente mult. por 8, 26473396⋅8..26474464⋅8, recebo 211787168..211795712, que está perto, mas está um pouco fora. Eu estou pensando que o segundo valor deve ser (26474465⋅8) -1 = 211795719, não sei por que.
slm
Alguma idéia de como obter os blocos em 512 unidades a partir de debugfs?
slm
Acabei fazendo os cálculos para converter de extensões para LBAs usando a mesma matemática acima.
slm
2

Acontece que converter de extensões para LBAs é bastante simples quando você entende de onde vêm os números. A resposta de @StephaneChazelas foi crítica para obter esse entendimento.

Saída de depuração original

Usando o exemplo a seguir mencionado na pergunta.

$ sudo debugfs -R "stat <6560281>" /dev/mapper/fedora_greeneggs-home
debugfs 1.42.7 (21-Jan-2013)
Inode: 6560281   Type: regular    Mode:  0664   Flags: 0x80000
Generation: 1999478298    Version: 0x00000000:00000001
User:  1000   Group:  1000   Size: 20
File ACL: 0    Directory ACL: 0
Links: 1   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x52be10c3:a640e994 -- Fri Dec 27 18:44:03 2013
 atime: 0x52be0fdc:bbf41348 -- Fri Dec 27 18:40:12 2013
 mtime: 0x52be0fe7:18a2f344 -- Fri Dec 27 18:40:23 2013
crtime: 0x52be0dd8:64394b00 -- Fri Dec 27 18:31:36 2013
Size of extra inode fields: 28
Extended attributes stored in inode body: 
  selinux = "unconfined_u:object_r:user_home_t:s0\000" (37)
EXTENTS:
(0):35304898

Com as informações de extensão, podemos fazer os seguintes cálculos. Mas precisamos de mais uma informação. O tamanho do bloco do sistema de arquivos subjacente. Você pode usar este comando para obtê-lo.

Tamanho do bloco

$ sudo tune2fs -l /dev/mapper/fedora_greeneggs-home | grep "Block size"
Block size:               4096

Convertendo de extensões em LBAs

Portanto, a principal transformação a ser reconhecida aqui é que os LBAs estão em unidades de 512 bytes e o debugfscomando acima, que relatou o número de extensões, está relatando isso em blocos de 4096 bytes.

Então, 4096/512 = 8. Portanto, precisamos multiplicar as extensões por 8 para convertê-las em valores LBA.

Portanto, a seguinte matemática nos dará nosso LBA inicial:

$ calc -d
; 35304898 * 8
    282439184
; 

Então, qual é o nosso final LBA? Para conseguir isso, precisamos reconhecer que nosso inode se encaixa dentro de um único bloco para que sua extensão final seja a mesma que sua extensão inicial. Para calcular o LBA final, podemos usar esta equação.

ending LBA = ( (extent + 1) * 8 ) - 1

Então, executando este cálculo:

$ calc -d
; ( (35304898 + 1) * 8 ) - 1
    282439191

Confirmando os resultados

Observando a hdparmsaída original :

 byte_offset  begin_LBA    end_LBA    sectors
           0  282439184  282439191          8

Vemos que as coisas combinam.

Outro exemplo

Apenas para ter certeza de que estamos certos, aqui está um arquivo maior como segundo exemplo.

$ ls -i util-linux-2.19.tar.bz2 
6559005 util-linux-2.19.tar.bz2

Aqui estão as extensões do inode.

$ sudo debugfs -R "stat <6559005>" /dev/mapper/fedora_greeneggs-home
...
EXTENTS:
(0-1068):26473396-26474464

Agora fazemos conversões de extensões para LBAs.

$ calc -d
; 26473396*8
    211787168
; (26474464+1)*8 - 1
    211795719

E nós confirmamos.

$ sudo hdparm --fibmap util-linux-2.19.tar.bz2 
...
 byte_offset  begin_LBA    end_LBA    sectors
           0  211787168  211795719       8552

E nós combinamos novamente.

slm
fonte