Como o Linux diferencia entre arquivos reais e inexistentes (por exemplo: dispositivo)?

28

Essa é uma pergunta de baixo nível, e entendo que talvez não seja o melhor lugar para perguntar. Mas, parecia mais apropriado do que qualquer outro site SE, então aqui vai.

Eu sei que no sistema de arquivos Linux, existem alguns arquivos , por exemplo: /usr/bin/bashé um que existe. No entanto, (tanto quanto eu entendo), alguns também não realmente existir como tal e são mais virtuais arquivos, por exemplo: /dev/sda, /proc/cpuinfo, etc. Minhas perguntas são (são dois, mas também intimamente relacionado para ser questões separadas):

  • Como o kernel do Linux descobre se esses arquivos são reais (e, portanto, os lêem no disco) ou não, quando um comando de leitura (ou tal) é emitido?
  • Se o arquivo não for real: como exemplo, uma leitura de /dev/randomretornará dados aleatórios e uma leitura de /dev/nullretornará EOF. Como funciona os dados a serem lidos nesse arquivo virtual (e, portanto, o que fazer quando / se os dados também são gravados no arquivo virtual) - existe algum tipo de mapa com ponteiros para separar os comandos de leitura / gravação apropriados para cada arquivo, ou mesmo para o próprio diretório virtual? Portanto, uma entrada para /dev/nullpoderia simplesmente retornar um EOF.
Joe
fonte
1
Quando o arquivo é criado, o kernel registra seu tipo. Arquivos de disco regulares são tratados de forma diferente de links simbólicos, dispositivos de bloco, dispositivos de caracteres, diretórios, soquetes, FIFOs, etc. É o trabalho do kernel a saber.
Jonathan Leffler
ver a PGE homem por mknod
Jasen
É como perguntar "como um interruptor de luz sabe se a luz está acesa?" O interruptor da luz é responsável por decidir se a luz está acesa.
Lightness Races com Monica

Respostas:

25

Portanto, existem basicamente dois tipos diferentes de coisas aqui:

  1. Sistemas de arquivos normais, que mantêm arquivos em diretórios com dados e metadados, da maneira familiar (incluindo links simples, links físicos e assim por diante). Estes são frequentemente, mas nem sempre, suportados por um dispositivo de bloco para armazenamento persistente (um tmpfs vive apenas na RAM, mas é idêntico a um sistema de arquivos normal). A semântica disso é familiar; leia, escreva, renomeie e assim por diante, todos funcionam da maneira que você espera.
  2. Sistemas de arquivos virtuais, de vários tipos. /proce /syssão exemplos aqui, assim como os sistemas de arquivos personalizados do FUSE, como sshfsou ifuse. Há muito mais diversidade nelas, porque na verdade elas se referem a um sistema de arquivos com semântica que, em certo sentido, é "personalizada". Portanto, quando você lê um arquivo em baixo /proc, na verdade não está acessando uma parte específica de dados que foi armazenada por outra coisa que foi gravada anteriormente, como em um sistema de arquivos normal. Você está essencialmente fazendo uma chamada do kernel, solicitando algumas informações geradas on-the-fly. E esse código pode fazer o que quiser, pois é apenas uma função em algum lugar implementando readsemântica. Assim, você tem o comportamento estranho dos arquivos /proc, como, por exemplo, fingir ser links simbólicos quando eles não são '

A chave é que /dev, na verdade, geralmente é do primeiro tipo. É normal nas distribuições modernas ter /devalgo como um tmpfs, mas em sistemas mais antigos era normal ter um diretório simples no disco, sem atributos especiais. A chave é que os arquivos abaixo /devsão nós do dispositivo, um tipo de arquivo especial semelhante aos soquetes FIFOs ou Unix; um nó de dispositivo possui um número maior e menor, e a leitura ou gravação deles está fazendo uma chamada para um driver do kernel, assim como a leitura ou gravação de um FIFO está chamando o kernel para armazenar sua saída em buffer em um pipe. Este driver pode fazer o que quiser, mas geralmente toca no hardware de alguma forma, por exemplo, para acessar um disco rígido ou reproduzir som nos alto-falantes.

Para responder às perguntas originais:

  1. Há duas questões relevantes para saber se o 'arquivo existe' ou não; é se o arquivo do nó do dispositivo existe literalmente e se o código do kernel que o suporta é significativo. O primeiro é resolvido como qualquer coisa em um sistema de arquivos normal. Os sistemas modernos usam udevou algo parecido para observar eventos de hardware e criar e destruir automaticamente os nós de dispositivos de /devacordo. Porém, sistemas mais antigos, ou construções leves e personalizadas, podem ter todos os nós de dispositivos literalmente no disco, criados com antecedência. Enquanto isso, quando você lê esses arquivos, está fazendo uma chamada para o código do kernel, que é determinado pelos números de dispositivos principais e secundários; se isso não for razoável (por exemplo, você estiver tentando ler um dispositivo de bloco que não existe), você receberá algum tipo de erro de E / S.

  2. A maneira como funciona o código do kernel para qual arquivo de dispositivo varia. Para sistemas de arquivos virtuais como /proc, eles implementam suas próprias funções reade write; o kernel apenas chama esse código, dependendo do ponto de montagem em que está, e a implementação do sistema de arquivos cuida do resto. Para arquivos de dispositivo, ele é enviado com base nos números de dispositivos principais e secundários.

Tom Hunt
fonte
Então, se, digamos, um sistema antigo tivesse sua energia desligada, os arquivos /devainda estariam lá, mas acho que eles seriam limpos quando o sistema inicializar?
20915 Joe
2
Se um sistema antigo (um sem criação de dispositivo dinâmico) fosse desligado, normalmente ou de forma anormal, os nós do dispositivo permaneceriam no disco, como qualquer arquivo. Então, quando a próxima inicialização acontecer, eles também permanecerão no disco e você poderá usá-los normalmente. Somente em sistemas modernos é que algo de especial acontece ao criar e destruir nós de dispositivos.
Tom Hunt
Portanto, um sistema mais moderno que não utiliza a tmpfscriaria e excluiria dinamicamente conforme necessário, por exemplo: inicialização e desligamento?
21415 Joe
3
devtmpfs, o /devsistema de arquivos no Linux moderno, é semelhante a um tmpfs, mas tem algumas diferenças para oferecer suporte udev. (O kernel faz a criação automática de nós por conta própria antes de entregá- udevlos, a fim de tornar a inicialização menos complicada.) Em todos esses casos, os nós dos dispositivos vivem apenas na RAM e são criados e destruídos dinamicamente conforme o hardware exige. Presumivelmente, você também pode usar udevem um disco comum /dev, mas nunca vi isso feito e não parece haver boas razões para isso.
Tom Hunt
17

Aqui está uma lista de arquivos do /dev/sda1meu servidor Arch Linux quase atualizado:

% ls -li /dev/sda1
1294 brw-rw---- 1 root disk 8, 1 Nov  9 13:26 /dev/sda1

Assim, a entrada de diretório no /dev/para sdatem um número de inode, 1294. É um arquivo real no disco.

Veja onde o tamanho do arquivo geralmente aparece. "8, 1" aparece em seu lugar. Este é um número de dispositivo principal e secundário. Observe também o 'b' nas permissões de arquivo.

O arquivo /usr/include/ext2fs/ext2_fs.hcontém essa estrutura C (fragmento):

/*
 * Structure of an inode on the disk
 */
struct ext2_inode {
    __u16   i_mode;     /* File mode */

Essa estrutura nos mostra a estrutura em disco do inode de um arquivo. Muitas coisas interessantes estão nessa estrutura; dê uma olhada longa nisso.

O i_modeelemento struct ext2_inodepossui 16 bits e usa apenas 9 para o usuário / grupo / outro, permissões de leitura / gravação / execução e outros 3 para setuid, setgid e sticky. Possui 4 bits para diferenciar tipos como "arquivo simples", "link", "diretório", "pipe nomeado", "soquete da família Unix" e "dispositivo de bloco".

O kernel do Linux pode seguir o algoritmo usual de pesquisa de diretório e tomar uma decisão com base nas permissões e sinalizadores no i_modeelemento. Para 'b', bloquear arquivos de dispositivos, ele pode encontrar os números de dispositivos principais e secundários e, tradicionalmente, usar o número do dispositivo principal para procurar um ponteiro para alguma função do kernel (um driver de dispositivo) que lida com discos. O número menor do dispositivo geralmente é usado como, por exemplo, o número do dispositivo do barramento SCSI ou o número do dispositivo EIDE ou algo parecido.

Algumas outras decisões sobre como lidar com um arquivo como /proc/cpuinfosão tomadas com base no tipo de sistema de arquivos. Se você fizer um:

% mount | grep proc 
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)

você pode ver que /procpossui o tipo de sistema de arquivos "proc". A leitura de um arquivo no /procfaz com que o kernel faça algo diferente com base no tipo do sistema de arquivos, assim como abrir um arquivo em um sistema de arquivos ReiserFS ou DOS faria com que o kernel usasse funções diferentes para localizar arquivos e localizar dados do arquivos.

Bruce Ediger
fonte
Você tem certeza de que apenas "arquivos reais no disco" têm um número de inode exibido? Eu entendo 4026531975 -r--r--r-- 1 root root 0 Nov 14 18:41 /proc/mdstatque claramente não é um "arquivo real".
precisa saber é o seguinte
7

No final das contas, todos são arquivos para o Unix, essa é a beleza da abstração.

A maneira como os arquivos são manipulados pelo kernel, agora essa é uma história diferente.

/ proc e atualmente / dev e / run (também conhecido como / var / run) são sistemas de arquivos virtuais na RAM. / proc é uma interface / windows para variáveis ​​e estruturas do kernel.

Eu recomendo a leitura do The Linux Kernel http://tldp.org/LDP/tlk/tlk.html e dos drivers de dispositivo Linux, terceira edição https://lwn.net/Kernel/LDD3/ .

Eu também gostei de Design e implementação do sistema operacional FreeBSD http://www.amazon.com/Design-Implementation-FreeBSD-Operating-System/dp/0321968972/ref=sr_1_1

Dê uma olhada na página relevante que pertence à sua pergunta.

http://www.tldp.org/LDP/tlk/dd/drivers.html

Rui F Ribeiro
fonte
obrigado, mudei um pouco a primeira pergunta depois que você comentou isso.
21415 Joe
Leia o último comentário, por favor.
Rui F Ribeiro
5

Além das respostas de @ RuiFRibeiro e @ BruceEdiger, a distinção que você faz não é exatamente a distinção que o kernel faz. Na verdade, você tem vários tipos de arquivos: arquivos regulares, diretórios, links simbólicos, dispositivos, soquetes (e eu sempre esqueço alguns, para não tentar fazer uma lista completa). Você pode ter as informações sobre o tipo de arquivo ls: é o primeiro caractere na linha. Por exemplo:

$ls -la /dev/sda
brw-rw---- 1 root disk 8, 0 17 nov.  08:29 /dev/sda

O 'b' no início indica que esse arquivo é um dispositivo de bloco. Um traço, significa um arquivo regular, 'l' um link simbólico e assim por diante. Essas informações são armazenadas nos metadados do arquivo e são acessíveis através da chamada do sistema, statpor exemplo, para que o kernel possa ler de maneira diferente um arquivo e um link simbólico, por exemplo.

Em seguida, você faz outra distinção entre "arquivos reais" /bin/bashe "arquivos virtuais", /proc/cpuinfomas lsinforma ambos como arquivos regulares, portanto a diferença é de outro tipo:

ls -la /proc/cpuinfo /bin/bash
-rwxr-xr-x 1 root root  829792 24 août  10:58 /bin/bash
-r--r--r-- 1 root wheel      0 20 nov.  16:50 /proc/cpuinfo

O que acontece é que eles pertencem a diferentes sistemas de arquivos. /procé o ponto de montagem de um pseudo-sistema de arquivos procfsenquanto /bin/bashem um sistema de arquivos em disco comum. Quando o Linux abre um arquivo (de maneira diferente dependendo do sistema de arquivos), ele preenche uma estrutura de dados fileque possui, entre outros atributos, uma estrutura de vários indicadores de função que descrevem como usar esse arquivo. Portanto, ele pode implementar comportamentos distintos para diferentes tipos de arquivos.

Por exemplo, estas são as operações anunciadas por /proc/meminfo:

static int meminfo_proc_open(struct inode *inode, struct file *file)
{
    return single_open(file, meminfo_proc_show, NULL);
}

static const struct file_operations meminfo_proc_fops = {
    .open       = meminfo_proc_open,
    .read       = seq_read,
    .llseek     = seq_lseek,
    .release    = single_release,
};

Se você observar a definição de meminfo_proc_open, poderá ver que essa função preenche um buffer na memória com as informações retornadas pela função meminfo_proc_show, cuja tarefa é coletar dados sobre o uso da memória. Esta informação pode ser lida normalmente. Sempre que você abre o arquivo, a função meminfo_proc_opené chamada e as informações sobre a memória são atualizadas.

lgeorget
fonte
3

Todos os arquivos em um sistema de arquivos são "reais" no sentido em que permitem E / S de arquivo. Quando você abre um arquivo, o kernel cria um descritor de arquivo, que é um objeto (no sentido de programação orientada a objetos) que age como um arquivo. Se você ler o arquivo, o descritor de arquivo executará seu método de leitura, que, por sua vez, solicitará ao sistema de arquivos (sysfs, ext4, nfs etc.) dados do arquivo. Os sistemas de arquivos apresentam uma interface uniforme para o espaço do usuário e sabem o que fazer para lidar com leituras e gravações. Os sistemas de arquivos, por sua vez, solicitam que outras camadas tratem de suas solicitações. Para um arquivo regular, por exemplo, um sistema de arquivos ext4, isso envolverá pesquisas nas estruturas de dados do sistema de arquivos (que podem envolver leituras de disco) e, eventualmente, uma leitura do disco (ou cache) para copiar dados no buffer de leitura. Para um arquivo em say sysfs, geralmente apenas sprintf () é algo para o buffer. Para um nó de desenvolvimento de bloco, ele solicitará ao driver de disco que leia alguns blocos e copie-os no buffer (os números principais e secundários informam ao sistema de arquivos para qual driver solicitar).

jpkotta
fonte