Reorganizando o UNIX para ser Confiável Jorrit N. Herder, Herbert

Propaganda
Reorganizando o UNIX para ser Confiável
Jorrit N. Herder, Herbert Bos, Ben Gras,
Philip Homburg, and Andrew S. Tanenbaum
Computer Science Dept., Vrije Universiteit Amsterdam
De Boelelaan 1081a, 1081 HV Amsterdam, The Netherlands
Resumo
Neste artigo, discutimos a arquitetura UNIX compatível com a geração de sistema MINIX 3,
que oferece confiabilidade além da maioria dos outros sistemas. Com quase todo o sistema
operacional em execução no modo usuário, serviços e drivers em cima de um kernel mínimo, o
sistema está completamente dividido em corpatimentos.
Movendo maior parte do código de usuário sem privilégios e processos de modo a restringir
os poderes de cada um, nós ganhamos isolamento de falhas e limitamos os danos que bugs podem
causar. Além disso, o sistema foi projetado para sobreviver e automaticamente recuperar-se de
forma transparente de falhas em módulos mais críticos, como drivers de dispositivo.
1. INTRODUÇÃO
Sistemas Operacionais são projetados com a expectativa de funcionar perfeitamente, mas
infelizmente a maioria dos sistemas operacionais de hoje falham com muita frequencia.
Como discutido da Seção 2, muitos problemas provem da concepção monolitica dos
sistemas. Todas as funcionalidades do sistema operacional, por exemplo, são executadas em modo
kernel sem isolamento a falhas adequado, assim qualquer erro pode potencialmente estragar todo o
sistema.
Acreditamos que reduzindo o kernel do sistema operacional e executando drivers e outros
componentes do núcleo em modo usuário ajudaria a minimizar os danos causados por bugs de
códigos. Essa estrutura , combinada com diversos mecanismos transparentes de recuperação de
erros e outras falhas, resulta em um sistema operacional multitarefa altemanete confiável, que ainda
se parece com o UNIX.
Para melhorar nosso conhecimento, somos os primeiros a explorar desta maneira, com uma
extrema decomposição do sistema operacional que é projetado para ser confiável, enquanto fornece
uma performance razoável. Algumas idéias e tecnologias foram utilizadas durante um longo tempo,
mas muitas vezes abandonadas por razões de desempenho. Nós acreditamos que chegou o momento
de reconsiderar as escolhas que foram feitas no projeto dos sistemas operacionais comuns.
1.1 Contribuição
A contribuição deste trabalho é o projeto e implementação de um sistema operacional que
leva o conceito de multi-servidores para sua conclusão lógica afim de fornecer uma plataforma de
computação comfiável. O objetivo concreto desta pesquisa é criar um sistema operacional UNIX
que possa sobreviver a falhas de compomentes críticos de forma transparente, tais como drivers de
dispositivos.
Como mencionado anteriormente, a resposta veio quebrando o sistema em unidades
gerenciáveis e através de um rígido controle de cada uma delas. O objetivo final é que um erro fatal,
por exemplo um driver de dispositivo, não deva gerar uma falha no sistema operacional; assim, uma
falha local deve ser detectada e falhando um componente, este deve ser automaticamente e
transparentemente substituído por uma nova cópia, sem afetar os processos do usuário.
2. TRABALHOS RELACIONADOS
Esta sessão dá uma visão geral do projeto, que tem os sistemas monolíticos em um extremo
e nosso no outro. Brevemente começamos uma pequena discussão – vinda dos sistemas monolíticos
e formas de confiabilidade. Então pesquisamos cada vez mais projetos modulares que acreditamos
que ajudará a tornar os sistemas operacionais mais confiáveis.
Costuma-se dizer que as máquinas virtuais e os exokernels propocionam isolamento e
modularidade suficientes para fazer um sistema seguro.
Contudo, estas tecnologias proporcionam uma interface para um sistema operacional, mas
não representa um sistema completo por si só. O sistema operacional sobre uma máquina virtual,
exokernel, ou hardware puro, pode ter uma das estruturas discutidas abaixo.
2.1 Ajustando a Confiabilidade de Sistemas Legados
Kernels monolíticos proporcionam uma abstração rica e poderosa. Todos os serviços do
sistema operacional são prestados por um simples programa que executa em modo kernel.
Projetos Monolíticos tem alguns problemas de confiabilidade. Todo código do sistema
operacional, por exemplo, executa com mais alto nível de privilégio sem o adequado isolamento de
falhas, de modo que qualquer erro pode, potencialmente, comprometer o sistema operacional. Com
milhões de linhas de código executável (LOC) e taxas de erro acima de 16 relatadas, ou 75 erros a
cada 1000 (LOC), os sistemas monolíticos são propensos ao erro. Rodando sem confiabilidade, o
código de terceiros dentro do kernel também compromete a confiabilidade do sistema, evidenciado
pelo fato que a taxa de erro dos controladores de dispositvo é 3 a 7 vezes superior do que em
qualquer outro código e 85% de todas as falhas do Windows são causadas por drivers.
Um projeto importante para melhorar a confiabilidade de sistemas como Linux é o Nooks. O
Nooks guarda os drivers de dispositvos dentro do kernel mas de forma transparente envolve-os em
um tipo de capa protetora para que os erros de drivers não possam se propagar para outras partes do
sistema operacional. Todo tráfego entre o driver e o resto do kernel é inspecioando pela camada de
confiabilidade.
Outro projeto usa maquinas virtuais para isolar os drivers de dispositivos do restante do
sistema. Quando um driver é chamado, uma diferente máquina virtual é executada em relação a
sistema principal para que todo um erro ou uma falha não polua o sitema principal. Além do
isolamento, esta técnica permite a reutilização do driver do dispositivo quando experimentado com
novos sistemas operacionais.
Um projeto recente rodou drivers de dispositivos Linux em modo usuário com poucas
mudanças no kernel do Linux. Este trabalho mostrou que os drivers podem ser isolados em
separado dos porcessos modo usuários sem degradar significavelmente o desempenho.
Embora isolar os drivers de dispositivos ajude a melhorar a confiabilidade do sistema
operacional, acreditamos ser adequado, um projeto totalmente modular desde o início, dando
melhores resultados. Isso inclui o encapsulamento de todos os componentes do sistema operacional
independentemente, em processos do modo usuário.
2.2 Projetanto Novo Design Modular
Em projetos modulares, o sistema operacional é dividido em um conjunto de servidores que
colaboram. Código não confiável como drivers de dispositivo podem ser executadas
independentemente dos módulos em modo usuário previnindo a difusão de falhas.
Uma abordagem é executar o sistema operacional em um único servidor modo-usuário em
cima de um microkernel.
Alguns sistemas comerciais como Symbian OS e QNX [13] são também baseados em vários
projetos de servidores, mas não usam uma extrema decomposição do sistema operacional como nós
fazemos. No Symbian OS, por exemplo, apenas o servidor de arquivo e a rede de trabalho e
telefonia são hospedados nos servidores modo-usuário, enquanto o kernel QNX ainda contém o
gerenciamento de processos e outras funções que poderiam ter sido isoladas em separado aos
processo de modo usuário.
Um recente sistema multi-servidor devenvolvido pela Microsoft Pesquisas é o Singularidade
(Singularity) [4]. Em contraste com outros sistemas, o Singularidade (Singularity) usa proteção da
linguagem ao invés da proteção do hardware oferecido pela MMU. O sistema pode ser
caracterizado como um microkernel rodando uma configuração verificável segura, servidor de
software isolado. Embora linguagem segura possa ser viável para construção de sistemas confiáveis,
Singularidade (Singularity) não está ainda compatível com as aplicações existentes.
3. NOSSA ARQUITETURA MULTI-SERVIDORES
Em nosso projeto, chamado de MINIX 3, o sistema operacional executa como configuração
de modo usuário de servidores e drivers sobre um pequeno núcleo, como ilustrado na Fig. 2. O
kernel é responsável pelo baixo nível e operações privilegiadas, como a programação da CPU e
MMU, tratamento de interrupções, e IPC, e comtém duas tarefas (SYS and CLOCK) para dar
suporte as partes modo usuário do sistema operacional.
O mais simples servidor, fornece as funcionalidades de sistema de arquivos (FS),
gerenciador de processos (PM), e gerenciador de memória (MM). O armazenamento de dados (DS)
é um pequeno servidor de banco de dados com funcionalidades publicadas. Finalmente, o servidor
de ressucitação (RS) mantém o controle de todos os servidores e drivers e pode reparar de forma
transparente o sistema quando determinadas falhas ocorrerem.
Cada componente do nosso projeto uma pequena e bem definida entidade com poder e
responsabilidade limitada, como na filosofia original do UNIX. O kernel consiste em menos de
4000 linhas de código executável (LoC) e o tamanho dos servidores aproximadamente 1000 a 3000
LoC por servidor, que facilita a compreensão e manutenção. O pequeno tamanho também torna
prático a verificação do código de forma manual ou através do uso de ferramentas de verificação.
Antes de nós continuarmos com a discussão dos componentes do núcleo, ilustraremos como
nosso sistema operacional multi-servidor atualmente trabalha. Quatro exemplos são dados abaixo:
(1) Uma aplicação que quer criar um processo filho chama o a função fork() da biblioteca,
que envia uma mensagem de solicitação ao gerenciador de processo (PM). PM verifica que um
processo aberto está disponível, solicita ao gerenciador de Memória (MM) para alocar memória e
instrui o kernel (SYS) para criar uma cópia do processo. Finalmente, PM envia a resposta e retorna
a função da biblioteca. Todas as mensagens passadas estão ocultas para a aplicação.
(2) A read() ou write() chamada para fazer I/O, é enviada para FS. Se o bloco solicitado está
no cache do buffer, FS solicita ao kernel (SYS) para copiá-lo para o usuário. De outra maneira ele
envia uma menssagem para o controlador de disco solicitando para recuperar o bloco de disco. O
controlador configura um alarme, comandando o controlador de disco através de um pedido de I/O
para o kernel (SYS), e aguarda a interrupção de hardware ou tempo limite.
(3) Servidores e drivers adicionais podem ser iniciados pela solicitação do sercidor de
ressucitação (RS). RS então cria um novo processo, define os provilégios do processo no kernel
(SYS) e, finalmente, executa o caminho dado dentro do processo filho (não é mostrado na figura).
Informações sobre o novo processo do sistema é publicado no armazenador de dados (DS), que
permite que as partes do sistema operacional subescrevam as atualizações de configuração do
sistema.
(4)Apesar de não ser chamada de um sistema, é interessante ver o que acontece se um
usuário ou processo do sistema provoca uma execeção fatal, por exemplo, devido a um inválido
ponteiro. Neste caso, o manipulador de exceção do kernel notifica PM, que transforma a exceção
em um sinal ou mata o processo quando manipulador não é registrado. Recuperação de falhas em
servidores e drivers é tratado pelo RS e é discutido abaixo.
3.1 O Kernel
O kernel pode ser caracterizado como um verdadeiro microkernel e oferece operações de
baixo nível que não podem ser feitas pelo modo-usuário sem privilégios. Primeiro, o kernel é
responsável pela gestão dos recursos de baixo nível e interação com o hardware. Por exemplo, isso
inclui manipulação de interrupção, programação da CPU e MMU, dispositivos I/O, e
escalonamento de processos.
3.2 Os Servidores do Espaço do Usuário
No topo do kernel, nós temos implementado um multi-servidor operando o sistema. Todos
os servidores e drivers rodam independentemente dos procesos modo usuário e são altamente
restritos no que podem fazer, apenas como aplicações de usuários normais.
O Gerente de Processo (PM), juntamente com FS, PM implementa a interface que está
disponível para programas de aplicações. PM é responsável pelo gerenciamento do processo tais
como criação e remoção dos mesmos, atribuindo IDs aos processos e prioridade, e controlando o
fluxo de execução. Além disso, a PM mantém a relação entre os processos, tais como grupo de
processos e linhas de parentesco pai-filhos. Este último, por exemplo, tem consequencia de sinalizar
os pais de processos terminados e contabilizar o tempo de CPU.
Embora o kernel forneça mecanismos de baixo-nível, por exemplo, configurar os
registradores da CPU, PM implementa toda a política de gerenciamento de processo. Como o kernel
está preocupado com todos os processos similares; tudo que ele faz é programar a mais alta
prioridade dos processos prontos. O gerenciamento de processos mais alto nível fornecido pelo PM
é responsável pela aparência do UNIX e do nosso sistema.
Gerente de Memoria (MM) Cada processo tem um segmento de texto, que pode ser
compartilhado com outros processsos que executam o mesmo programa. A Processos do sistema
podem ser concedido acesso adicional a segmentos de memória, tais como memória de vídeo ou
memória RAM. Além disso, eles são autorizados a solicitar blocos de memória livre.
O segmento de texto de todos os processos tem proteção de apenas leitura, o que torna a
vunerabilidade de estouro de buffer mais difícil de ser explorada por vírus e worms, já que o código
injetado não pode ser executado diretamente.
Embora o kernel seja responsável por esconder os detalhes de hardware como programação
do MMU, MM faz o gerenciamento da memória real. MM mantém uma lista com as regiões de
memória livre, e pode alocar ou criar segmentos de memória para outros serviços do sistema.
Atualmente MM está integrado no PM, mas o trabalho está em andamento para dividí-lo e
colocá-lo para fora, oferecendo capacidade de memória virtual.
Servidor de Arquivos (FS) gerencia os arquivos do sistema. É um servidor de arquivos
comum manuseia chamadas como open() (abrir), read() (ler) e write() (escrever).
Atualmente, nosso sistema oferece um sistema de arquivos – nosso próprio sistema de
arquivos nativo – mas o trabalho está em andamento para transformar o FS em um servidor virtual
de sistema de arquivos (VFS), que surporta múltiplos sistemas de arquivos, diferente do servidor de
arquivos do sistema. Ambos VFS e cada servidor de arquivo será executado com um isolado,
processo de modo usuário.
Servidor de Ressucitação (RS) RS é o componente central responsável pelo gerenciamento
de todos os servidores do sistema operacional e drivers. Enaquanto o PM é responsável pelo
gerenciamento dos processos em geral, o RS trata apenas os processos privilegiados: servidores e
drivers. Ele age como um guardião e garante a vida do sistema operacional. A administração do
sistema de processos também é feito através do RS. Um programa utilitário, serviço, fornece ao
usuário uma interface conveniente para RS. Ele permite que o administrador inicie e pare os
serviços do sistema e redefina a politica que é executada em certo evento, incluindo erros de driver.
Durante a inicialização do sistema RS adota todos os processos boot como seus filhos.
Processos do sistema que são inicializados mais tarde, também tornam-se filhos do RS. Isso garante
uma detecção de erros imediata. Além disso, RS pode verificar a atividade do sistema. RS faz uma
chegagem periódica do status, e espera uma resposta no próximo período. A ausência de resposta
causará a morte do processo.
Sempre que um problema é detectado, RS pode substituir o componente com defeito por
uma nova cópia, mas a ação tomada pode ser diferente para cada servidor e cada driver. A política
associada pode reiniciar o componente que falhou, colocar a falha no registro do sistema, efetuar
um backup (cópia de segurança) da imagem do núlceo do componente que falhou para uma
posterior inspeção, enviar um e-mail para um sistema remoto administrador, ou outra coisa. Se a
falha ocorrer novamente, um protocolo poderia ser usado para previnir a queda do sistema com
repetidas recuperações.
Amazenamento de Dados (DS) DS é um pequeno servidor de banco de dados que serve
para dois propósitos. Primeiro, processos do sistema podem usá-lo para armazenar alguns dados
particulares. Esta redundância é útil em função a tolerância a falhas. Uma reinicialização do serviço
do sistema, por exemplo, pode pedir o estado atual que perdeu quanto caiu. Esses dados não são
acessíveis ao público, mas apenas para os processos que os armazenaram.
Segundo, o mecanismo de assinatura pública (publish-subscribe) é a ligação entre os
componentes do sistema operacional.
Drivers de Dispositivos – Todo os sistemas operacionais escondem o verdadeiro hardware
embaixo da camada de drivers de dispositivos. Para começar e provar nossos princípios de trabalho
na prática, temos implementados drivers para ATA, S-ATA, floppy, RAM, teclados, monitores,
audio, impressoras, conexão serial, várias placas Ethernet, etc.
Embora os drivers de dispositivos possam ser muito exigentes, tecnicamente, eles não são
muito interessantes dentro do projeto do sistema operacional. O que é importante, porém, é que
cada um dos nossos são executados como um processo modo-usuário independente para previnir
que falhas se espalhem e torna-se fácil substituir drivers com falhas sem necessidade de reiniciar.
Estamos conscientes que nem todos os erros podem ser resolvidos, reiniciando um driver
que falhou, porém os principais bugs tendem a ser erros de tempo ou vazamentos memória em vez
de erros de algorítmos, e fazem reiniciar o trabalho frequentemente. Além disso, nosso sistema pode
tomar outras medidas, bem como, identificar o driver que é responsável pela falha e notificar um
administrador remoto.
4. CONFIABILIDADE
Um dos pontos fortes do nosso sistema é que ele move os drivers de dispositivos e outras
funcionalidades do sistema operacional para fora do kernel dentro dos processos de modo-usuário
sem privilégios e introduz barreiras protetoras entre todos os módulos. Esta forte compartimentação
melhora a confiabilidade do sistema em vários aspectos [15, 16]. Falhas são devidamente isoladas e
muitas vezes o sistema pode recuperar-se por reiniciar o componente que falhou ao invés de
reiniciar o computador inteiro.
4.1 Isolamento de Falhas
O kernel e o hardware MMU garante que os processos são totalmente isolados. Cada
servidor e driver é encapsulado num endereço privado que é protegido pelo hardware MMU.
Tentativas de acesso ilegal são capturadas, assim como para as aplicações de usuários. Processos
podem trocar dados de forma controlada.
O modo-usuário dos componentes do sistema operacional não executa com privilégios de
super-usuário. Em vez disso, eles recebem usuário sem privilégios e um identificador de grupo para
restringir o acesso ao sistema de arquivo e chamadas do sistema. Além disso, cada usuário, servidor,
processo de driver tem uma política de restrição, de acordo com os princcípios de menos
autoridade. As políticas são definidas pelo RS e o kernel as aplica em tempo de execução.
Driver para acessar portas I/O e linhas de IRQ são atribuídos quando eles são iniciados.
Desta forma, digamos, o driver da impressora tenta escrever nas portas I/O de discos, o kernel
negará o acesso.
4.2 Flexibilidade das Falhas
Enquanto nós não reivindicamos que nosso sistema está livre de erros, em muitos casos,
podemos recuperar de falhas devido a erros de programação ou de tentativas de explorar
vulnerabilidades, transparente às aplicações e sem intervenção do usuário. Como discutido na Seção
3, o servidor RS executa uma política quando detecta uma falha e pode substituir automaticamente
um processo do sistema que falhou por uma nova cópia.
O pressuposto de nossa abordagem é que falhas são transitórias e que reiniciar o componete
permite solucionar o problema. A falha defininida que trata RS, como erros internos, falhas de
sincronismo, envelecimento de bugs, e falhas de ataque. Erros internos significam que um processo
do sistema encontra uma exceção, por exemplo, porque ele referencia um ponteiro inválido.
EM princípio, RS guarda ambos os servidores e drivers, mas nosso sistema atualmente é
projetado principalmente para lidar com falhas de drivers de dispositivos. Se um dos servidores do
núcleo discutidos na seção anterior de falhar, a recuperação não é ainda possível e o sistema será
prejudicado. Por exemplo, um queda de PM ou FS que juntos implementam afetará diretamente os
programas de aplicação. No entanto, dado que, normalmente cerca de 70% dos sistemas
operacionais consistem em drivers de dispositivos e que eles tem uma taxa de erro de 3 a 7 vezes
maior que o código comum [7], nós abordamos uma importante classe de problemas com nosso
projeto.
5. PERFORMACE
Os sistemas modulares tem sido criticados por décadas porque seu desempenho apresenta
problemas. Sistemas Multiservidor modernos, no entanto, tem provado que um desempenho
competitivo pode ser realizado [3, 11]. Nós temos feito medições extensivas de nossos sistemas (um
um Athlon 2.2 Ghz), mostrando que a sobrecarga de desempenho em comparação com os sistemas
baseados em drivers no kernel está limitado a 5-10%. A chamada de sistema mais simples, getpid(),
leva 1,011 microsegundos, que inclui passar duas mensagens e duas trocas de contexto. Reconstruir
o sistema completo, que é um trabalho fortemente vinculado ao disco, tem uma sobrecarga de 7%
em relação ao sistema básico com driver de dispositivo no kernel.
6. CONCLUSÕES
Nossa principal contribuição de pesquisa apresentada neste artigo é que ralmente
construímos um sistema operacional multi-servidor UNIX-compatível altamente confiável com uma
perda de desempenho se somente 5% a 10%.
Para alcançar alta confiabilidade reorganizamos o projeto monolítico que é comum a vários
sistemas operacionais UNIX. Nosso projeto consiste em um pequeno kernel rodando o rodando o
sistema operacional inteiro como um coleção independente, isolado, de processos modo-usuário. O
kernel implementa apenas os mecanismos mínimos, tais como manipulação de interrupção, IPC,
aplicação de política.
7. DISPONIBILIDADE
O sistema é chamado MINIX 3, porque nós começamos com o MINIX 2 como base e então
foi modificado muito fortemente. É gratuito, software de cófigo aberto, disponível através da
Internet. Você pode baixar o MINIX 3 da página oficial em: http://www.minix3.org/, que também
contém o código-fonte, documentação, notícias, contribuiu pacotes de software, e muito mais. Mais
de 75.000 pessoas fizeram o download a imagem de CD-ROM desde o lançamento (Outubro de
2005), resultando em um grande e crescente comunidade de usuários que se comunica com o
newgroup USENET comp.os.minix. MINIX 3 está sendo ativamente desenvolvidas, e sua ajuda e
feedback são muito bem-vindos.
Download