Baixe o app para aproveitar ainda mais
Prévia do material em texto
Sistemas de Arquivos Podemos pensar num disco como uma sequência linear de blocos fixos que possui operações de ler e escrever em um bloco k. Arquivos são unidades lógicas de informação criadas por processos. Um disco pode conter milhões destes de forma independente e é válido associar como se cada arquivo fosse um endereço no disco. Processos podem ler arquivos existentes ou criar novos. Informações inseridas nos arquivos devem ser persistidas e um arquivo só deve ser excluído se o proprietário dele explicitamente fizer. 1. Arquivos Nomeação de Arquivos: quando um processo cria um arquivo, ele lhe dá um nome. O arquivo ficará disponível mesmo se o processo for encerrado e pode ser acessado por outros arquivos através do seu nome. Regras de nomeação são específicas de cada sistema de arquivo, mas de maneira geral, uma sequência de caracteres e até mesmo símbolos especiais são válidos. Alguns sistemas de arquivos distinguem letras minúsculas de maiúsculas (o UNIX pertence ao primeiro, o MS-DOS ao segundo). Os sistemas de arquivos permitem nomes segmentados, como a extensão de um arquivo, que vem depois de um ponto (main.java) e essa extensão diz algo sobre o arquivo. O UNIX permite várias extensões (index.html.zip significa que o arquivo é uma página html compactada). Extensões são convenções, o SO não se importa com elas (mas um programa pode exigir). Estrutura de Arquivos: o SO trata o arquivo como uma sequência de bytes. Qualquer abstração maior é feita em alto nível. Eles podem ser organizados como uma sequência de bytes, como uma sequência de registros (comum nos sistemas de cartão dos anos 80) ou como uma árvore. Tipos de Arquivos: todos os SOs tem arquivos regulares e diretórios. Arquivos regulares são aqueles que contém informação do usuário. Diretórios são arquivos do sistema para manter a estrutura do sistema de arquivos. Arquivos especiais de caracteres (tipo c, por ex /dev/tty) são referentes a arquivos para E/S, e arquivos especiais de blocos (tipo b, por ex /dev/sda) são usados para modelar discos. Arquivos geralmente são escritos em ASCII. Isso facilita pois o arquivo pode ser lido como ele foi escrito em qualquer editor e programas que usam como entrada e saída podem ter uma interface mais fácil. Arquivos binários são mais difíceis e geralmente possuem uma estrutura que apenas o programa que lida com eles conhece. Acesso aos Arquivos: os primeiros SOs usavam um sistema de acesso sequencial, onde era possível apenas ler um arquivo do começo, não sendo possível pular ou ler fora de ordem (fazia sentido por causa das fitas magnéticas). Já nos discos, os arquivos são acessados de maneira aleatória e podem ser especificados de qual posição do arquivo devem abrir. Ou você usa uma função read passando a posição desejada ou uma o seek, que recebe a posição e vai para esta posição no arquivo atual. Atributos de Arquivos: nome, data (criação, modificação). Proteção, senha, criador e proprietário são atributos referentes a segurança do arquivo. Há flags que possuem uso específico (como bit de arquivo oculto). Operações com Arquivos: - create - delete - open - close - read: usado para ler, geralmente os bytes vem da posição atual - write: geralmente feito na posição atual, que é o final. Se este for o caso, o arquivo cresce, caso contrário, os bytes posteriores são sobrescritos e perdidos para sempre - append: tipo um write mas que só escreve no final - seek: para arquivos de acesso aleatório, reposiciona o cursor do arquivo para um local específico dele - get attributes: para os processos que precisam dos metadados dos arquivos - set attributes - rename 2. Diretórios Usados para controlar os arquivos (eles em si são arquivos também). Sistemas de diretório em nível único: basicamente um único diretório que contém todos os arquivos. Usado em sistemas antigos e em sistemas embarcados atuais (pequenos, simples). Era rápido para procurar arquivos por que só tinha um lugar para buscar mesmo. Sistemas de diretórios hierárquicos: a idéia é que os arquivos sejam organizados em uma árvore de diretórios, onde cada subárvore contém arquivos que fazem sentidos estarem alí. Nomes de caminhos: há duas maneiras. Na primeira, o arquivo recebe um nome de caminho absoluto, que é o caminho da raiz até ele (/usr/antunes/documents/oi.txt). Sempre começam com o diretório raiz e são únicos. A segunda maneira é chamada de nome de caminho relativo. Funciona quando um usuário diz que um diretório é o diretório atual de trabalho dele, então o nome dos arquivos não começam da raiz mas sim desse diretório. Cada processo tem seu próprio diretório de trabalho. Operações com diretórios: create (cria vazio, exceto pelo "." e ".."), delete (apenas um diretório vazio pode ser removido), opendir (para ler um diretório, primeiro abre), closedir, readdir, rename, link (permite que um arquivo esteja em mais de um diretório), unlink. 3. Implementação do Sistema de Arquivos Esquema do Sistema de Arquivos: sistemas de arquivos podem ser armazenados em discos, que podem conter várias partições. No setor inicial do disco, há a MBR. Ela tem os endereços de início e fim de cada partição. O primeiro bloco do sistema de arquivos é o superbloco. Ele contém todos os parâmetros-chave para o sistema de arquivos e é carregado na memória toda vez que o sistema operacional é carregado. Informações típicas no superbloco incluem um número mágico para identificar o tipo de sistema de arquivos, número de blocos e outras informações administrativas. O próximo bloco contém informações a respeito de blocos disponíveis, que pode ser seguido pelos i-nodes e depois o diretório raiz. Por fim, o restante do disco contém os demais arquivos e diretórios. Implementando arquivos: a alocação contígua é o esquema mais simples de armazenar os arquivos, fazendo através de uma execução contígua de blocos de disco. Ela sempre começa a armazenar um arquivo no começo do bloco. Isso, porém, pode desperdiçar espaço se o arquivo não ocupar um bloco inteiro (isso leva a fragmentação). Suas vantagens são a facilidade de implementação (para buscar os blocos de um arquivo basta saber onde ele começa e somar da parte que você quer), além de ser muito rápido visto que os blocos estão em sequência, então a operação de leitura será realizada sem necessidade de novas rotações. A alocação por lista encadeada é outro esquema, onde os blocos são organizados como uma lista encadeada onde a primeira palavra do bloco é um apontador para o próximo. Essa técnica basicamente anula o problema de fragmentação, mas torna as consultas a endereços aleatórios extremamente custosa. Além disso, a quantidade de dados por bloco não é mais uma potência de dois (já que o bloco precisa guardar a referência do próximo), o que atrapalha o salvamento de dados pois os programas são preparados para lidar com dados dessa ordem. A lista encadeada usando uma tabela na memória ajuda a resolver os dois grandes problemas do método anterior. Agora, os blocos ficam com seu espaço inteiro para dados e a lista de encadeada de endereços de cada arquivo ficam guardados em uma tabela na memória. A busca não é tão lenta já que os dados estão em memória. O problema é que, para discos grandes, a tabela fica gigante. Era comum usar isso em sistemas antigos que tinhampouco armazenamento. Os i-nodes são estruturas de dados que resolvem esses problemas. Eles contém uma lista de atributos do arquivo, bem como os endereços do disco e precisam estar na memória apenas quando esses arquivos estão abertos. Assim, é escalável para grandes volumes. Implementando diretórios: a principal função do sistema de diretórios é mapear o nome do arquivo ao endereço do bloco do disco. As informações sobre os arquivos do diretório podem ser colocadas na entrada do diretório ou em estruturas como o i-node. Porém, essas estruturas de tamanho variável podem gerar fragmentação de disco. Uma opção é tratar os arquivos com um cabeçalho de informações fixas no início do bloco e as informações variáveis, como o nome do arquivo, numa heap no final do bloco. Isso permite que, quando um arquivo seja removido, outro possa ser inserido sem problema. Buscas em diretórios com muitos arquivos podem se tornar lentas. Uma solução é usar uma função de espalhamento, onde dado o nome do arquivo, essa função irá calcular uma posição de onde o arquivo está. A ideia é semelhante a uma hashtable (apenas semelhante) e deve ser usada apenas quando sabe-se que o sistema conterá diretórios com muitos arquivos. Arquivos compartilhados: um problema referente a arquivos compartilhados é como os blocos serão disponibilizados para os diferentes usuários. Se o sistema realizar uma cópia da informação dos blocos, a edição de um usuário não será refletido para outro e assim não há compartilhamento. Uma solução seria o uso de estruturas como os i-nodes, onde os usuários receberiam os i-nodes e as modificações seriam acrescentadas neles. Porém, isso pode levar a problemas caso o dono do arquivo o exclua e alguém esteja editando: o arquivo deve ser excluído e o usuário fica com um i-node inválido? Outra solução é o uso de ligações simbólicas, mas isso também gera complexidade para manter todos os links. Sistemas de arquivos estruturados em diário (logs): muitas operações simples em um disco apresentam um custo alto. Sempre que um arquivo novo é criado, vários blocos precisam ser escritos e se isso for feito aos poucos, a taxa de utilização do disco é baixa. Assim, a ideia desse sistema de arquivos é juntar as informações de escrita em memória e quando tiver um tamanho considerável, as guarda em disco. Esse salvamento é na forma de um diário, onde no início de cada diário há informações sobre o que foi escrito ali. Os i-nodes ainda existem e eles são indexados através de um mapa. Há uma rotina, chamada de limpador, que é executada circularmente no diário para encontrar i-nodes e informações inválidas, a fim de excluí-las. Sistemas de arquivos journaling: a ideia é que o sistema mantenha um diário das atividades do disco antes mesmo delas acontecerem. Assim, em caso de falha, o sistema pode verificar no diário o que estava para acontecer e concluir a ação. Quando uma modificação há de ser feita no disco, o sistema primeiro registra e persiste todas as ações a serem feitas no diário e só depois começa a executar as operações de fato. Quando as operações são finalizadas com sucesso, a entrada no diário é apagada. Em caso de erro, o sistema verifica no diário e reexecuta as operações. Para isso, as operações devem ser idempotentes. 3. Implementação do Sistemas de Arquivos do Linux Para abstrair o sistema de arquivos das chamadas do sistema, o linux possui um sistema de arquivos virtual. A VFS oferece uma interface para operações simples. O ext2 é um dos sistemas de arquivos mais populares do Linux. Ele organiza o disco iniciando por um bloco com informações sobre a inicialização do sistema. Depois, vem o superbloco, que contém informações sobre o sistema de arquivos, quantidade de i-nodes, alguns apontadores para blocos livres. A próxima parte são os i-nodes, que, como vimos, descrevem os arquivos. A próxima parte são os blocos de arquivos em si. Arquivos não são necessariamente escritos em série se eles ocuparem mais de um bloco. 4. Gerenciamento e Otimização de Sistemas de Arquivos Gerenciamento do espaço em disco: blocos tem tamanho fixo e os arquivos não são guardados em blocos consecutivos. Tamanho do bloco: blocos muito pequenos evitam desperdício de espaço, mas nem todos os arquivos cabem em um só bloco e ler muitos blocos é um custo maior. Blocos grandes demais podem gerar fragmentação. Monitoramento dos blocos livres: uma opção é usar uma lista encadeada de blocos livres ou um mapa de bit. Backups: importante saber quais arquivos copiar (nunca fazer cópia de diretórios de dispositivos removíveis, por exemplo). Além disso, é interessante uma estrutura que permita snapshot do sistema de arquivos pois o backup demora muito a ser feito e esse snapshot auxilia na cópia. Cópias incrementais ajudam a manter a velocidade, visto que depois que há um backup de tudo, basta atualizar os arquivos que foram modificados. Há também o problema de blocos defeituosos, que, obviamente, tornam a cópia dele impossível. Consistência:
Compartilhar