Como posso (facilmente) mapear um nó de dispositivo de bloco para o diretório em que está montado?

3

Eu preciso encontrar (em C ou C ++) o espaço usado em um sistema de arquivos (Linux) ao ser fornecido apenas com o nome do dispositivo de bloco de disco e o número da partição.

Para a maioria dos sistemas de arquivos, posso ir:

  • Crie um nome de desenvolvedor como /dev/<block><part> ou /dev/<block>p</part> , conforme o que existir
  • Pesquise /proc/mounts para esse dispositivo e obtenha o ponto de montagem
  • Use statvfs() nesse ponto de montagem

Embora isso pareça um pouco longo, é adequado. No entanto, há uma ressalva:

Minha raiz está montada em /dev/root , em vez do nome real do dispositivo de bloco. Exceto que não há /dev/root - o nó não existe. Agora, posso fazer referência a um nome de bloco /dev/<whatever> usando stat("/"...) para obter o ID do dispositivo e dividi-lo em números maiores / menores e, em seguida, procure /sys/dev/block/<maj>:<min>/uevent na entrada DEVNAME= .

Mantendo uma função completamente genérica, o método seria expandido para:

  1. Crie o nome do dispositivo certo de /dev/<block><part> ou /dev/<block>p<part> , o que existir
  2. Para cada entrada em /proc/mounts :
    1. Extraia o ponto de montagem
    2. Obtenha o par maior / menor de stat()
    3. Pesquise o nome do dispositivo pai em /sys/dev/block/<maj>:0/uevent
    4. Compare o nome do dispositivo com o nome do dispositivo de bloco e o menor com o número da partição
    5. Se for uma correspondência, obtenha o espaço usado em statvfs()

Isso está ficando realmente sem fôlego agora, e eu não gosto disso. Sim, deve funcionar, mas está longe de ser ideal.

Então - existe uma interface mais simples para fazer isso? Alguma maneira de interagir diretamente com a tabela de montagem no kernel? Alguma maneira de obter, para cada sistema de arquivos montado, o dispositivo de bloco (major / menor seria bom), e o caminho é montado em (juntamente com outras informações provavelmente) em uma struct?

Eu sei que existem mount() e umount() funções, mas existe uma função "tell me what is mounted"() ?

    
por Majenko 04.05.2015 / 22:22

1 resposta

2

Meu primeiro comentário é tudo o que você afirma que funcionará somente se o sistema de arquivos no dispositivo em que você está interessado estiver montado. Mas eu acho que você sabe disso e aceita essa limitação.

O método que você propõe parece bastante completo e acho que vai pegar todos os casos.

Sobre a procura do ip em /sys/dev/block :

  • Você não está procurando <maj>:0 ao declarar. Você está procurando <major>:<minor> .
  • Esteja preparado para o caso em que você não o encontra. Alguns sistemas de arquivos como /proc e tipo tmpfs e nfs não possuem dispositivos associados. Você vai querer ignorá-los, pois eles não podem corresponder ao dispositivo de bloco que lhe interessa.

Ao procurar o nome do dispositivo, não digitalize /sys/dev/block/<major>:<minor>/uevent . Em vez disso, para um readlink() on /sys/dev/block/<major>:<minor> em si e obter o nome de base do resultado. Você deve obter o mesmo resultado, mas é um pouco mais limpo e mais eficiente.

Se você quiser pesquisar vários dispositivos, deverá varrer /proc/mounts e fazer a consulta /sys inteira apenas uma vez e armazenar em cache os resultados da próxima consulta de dispositivo.

Não há nenhuma chamada de sistema show_me_mounts() . No Linux, é para isso que o /proc/mounts serve. Mas como você percebeu, não é perfeito. Geralmente você não verá o problema /dev/root virtual / inexistente com uma inicialização baseada em initramfs totalmente moderna.

Editar com base na sua exigência de encontrar o disco inteiro correspondente a cada partição.

Para obter o dispositivo de bloco "externo" (= disco inteiro) dado um dispositivo de bloco "interno" (= partição), você não pode apenas alterar o número do dispositivo menor para 0.

A maneira correta de fazer isso se você encontrou 8 principais e 1 menor é procurar neste arquivo:

/sys/dev/block/8:1/../dev

Isso produzirá 8:0 , mas sem a suposição incorreta de que o ID do dispositivo secundário sempre pode ser alternado para 0.

Se você obtiver ENOENT tentando abri-lo, é porque o tipo de dispositivo de bloco em questão não tem uma hierarquia interna / externa ou o ID de dispositivo secundário não corresponde a um dispositivo interno.

    
por 04.05.2015 / 22:57