Estou tentando entender como uma função, digamos mkdir
, funciona, olhando para a fonte do kernel. Esta é uma tentativa de entender os componentes internos do kernel e navegar entre várias funções. Eu sei que mkdir
está definido em sys/stat.h
. Eu encontrei o protótipo:
/* Create a new directory named PATH, with permission bits MODE. */
extern int mkdir (__const char *__path, __mode_t __mode)
__THROW __nonnull ((1));
Agora eu preciso ver em qual arquivo C essa função está implementada. No diretório de origem, tentei
ack "int mkdir"
que exibido
security/inode.c
103:static int mkdir(struct inode *dir, struct dentry *dentry, int mode)
tools/perf/util/util.c
4:int mkdir_p(char *path, mode_t mode)
tools/perf/util/util.h
259:int mkdir_p(char *path, mode_t mode);
Mas nenhum deles corresponde à definição em sys/stat.h
.
Questões
- Qual arquivo tem a
mkdir
implementação? - Com uma definição de função como a acima, como posso descobrir qual arquivo tem a implementação? Existe algum padrão que o kernel segue na definição e implementação de métodos?
NOTA: Estou usando o kernel 2.6.36-rc1 .
linux-kernel
source
system-calls
Navaneeth KN
fonte
fonte
Respostas:
As chamadas do sistema não são tratadas como chamadas de função regulares. É necessário um código especial para fazer a transição do espaço do usuário para o espaço do kernel, basicamente um pouco de código de montagem embutido injetado no seu programa no site de chamada. O código do lado do kernel que "captura" a chamada do sistema também é algo de baixo nível que você provavelmente não precisa entender profundamente, pelo menos a princípio.
No
include/linux/syscalls.h
diretório de origem do seu kernel, você encontra o seguinte:Então
/usr/include/asm*/unistd.h
, você encontra o seguinte:Este código está dizendo
mkdir(2)
é a chamada de sistema # 83. Ou seja, as chamadas do sistema são chamadas por número, não por endereço, como ocorre com uma chamada de função normal em seu próprio programa ou para uma função em uma biblioteca vinculada ao seu programa. O código de cola de montagem em linha que mencionei acima usa isso para fazer a transição do espaço do usuário para o kernel, levando seus parâmetros junto com ele.Outra evidência de que as coisas são um pouco estranhas aqui é que nem sempre existe uma lista estrita de parâmetros para chamadas do sistema:
open(2)
por exemplo, pode-se usar 2 ou 3 parâmetros. Isso significa queopen(2)
está sobrecarregado , um recurso do C ++, não do C, mas a interface do syscall é compatível com o C. (Isso não é o mesmo que o recurso varargs de C , que permite que uma única função receba um número variável de argumentos.)Para responder sua primeira pergunta, não existe um arquivo único onde
mkdir()
exista. O Linux suporta muitos sistemas de arquivos diferentes e cada um tem sua própria implementação da operação "mkdir". A camada de abstração que permite que o kernel oculte tudo isso atrás de uma única chamada do sistema é chamada de VFS . Então, você provavelmente quer começar a pesquisarfs/namei.c
, comvfs_mkdir()
. As implementações reais do código de modificação do sistema de arquivos de baixo nível estão em outro lugar. Por exemplo, a implementação ext4 é chamadaext4_mkdir()
, definida emfs/ext4/namei.c
.Quanto à sua segunda pergunta, sim, existem padrões para tudo isso, mas nenhuma regra. O que você realmente precisa é de um entendimento bastante amplo de como o kernel funciona, a fim de descobrir onde você deve procurar qualquer chamada específica do sistema. Nem todas as chamadas do sistema envolvem o VFS; portanto, as cadeias de chamadas do lado do kernel nem todas são iniciadas
fs/namei.c
.mmap(2)
, por exemplo, iniciamm/mmap.c
, porque faz parte do subsistema de gerenciamento de memória ("mm") do kernel.Eu recomendo que você obtenha uma cópia de " Entendendo o Kernel do Linux ", de Bovet e Cesati.
fonte
Documentation
subdiretório da árvore de origem do kernel com o qual estou trabalhando....
como qualquer função de variável. Obviamente, isso é implementado no nível libc. Pode passar 0 ou um valor de lixo para a ABI do kernel quando o terceiro parâmetro não for usado.Provavelmente, isso não responde diretamente à sua pergunta, mas achei
strace
muito legal tentar entender as chamadas de sistema subjacentes, em ação, feitas até para os comandos mais simples do shell. por exemploAs chamadas do sistema para o comando
mkdir mynewdir
serão enviadas para trace.txt para seu prazer.fonte
Um bom lugar para ler a fonte do kernel do Linux é a referência cruzada do Linux (LXR) ¹. As pesquisas retornam correspondências digitadas (protótipos de funções, declarações de variáveis etc.), além de resultados de pesquisa de texto livre, por isso é mais prático do que um mero grep (e mais rápido também).
O LXR não expande as definições do pré-processador. As chamadas do sistema têm seu nome mutilado pelo pré-processador em todo o lugar. No entanto, a maioria das chamadas de sistema (todas?) São definidas com uma das
SYSCALL_DEFINEx
famílias de macros. Comomkdir
leva dois argumentos, uma pesquisaSYSCALL_DEFINE2(mkdir
leva à declaração domkdir
syscall :ok,
sys_mkdirat
significa que é omkdirat
syscall; portanto, clicar nele apenas leva à declaraçãoinclude/linux/syscalls.h
, mas a definição está logo acima.O principal trabalho de
mkdirat
é chamarvfs_mkdir
(VFS é a camada genérica do sistema de arquivos). Clique aqui para mostrar dois resultados de pesquisa: a declaração eminclude/linux/fs.h
e a definição algumas linhas acima. O principal trabalho dovfs_mkdir
é chamar a implementação específica do sistema de arquivos:dir->i_op->mkdir
. Para descobrir como isso é implementado, você precisa recorrer à implementação de um sistema de arquivos individual e não há uma regra rígida - pode até ser um módulo fora da árvore do kernel.¹ LXR é um programa de indexação. Existem vários sites que fornecem uma interface para o LXR, com conjuntos ligeiramente diferentes de versões conhecidas e interfaces da web ligeiramente diferentes. Eles tendem a ir e vir, por isso, se você não estiver disponível, faça uma pesquisa na web por “referência cruzada linux” para encontrar outro.
fonte
As chamadas do sistema geralmente são agrupadas na
SYSCALL_DEFINEx()
macro, e é por isso que um simplesgrep
não as encontra:O nome da função final após a expansão da macro acaba sendo
sys_mkdir
. ASYSCALL_DEFINEx()
macro adiciona itens padrão, como código de rastreamento que cada definição de syscall precisa ter.fonte
Nota: o arquivo .h não define a função. É declarado nesse arquivo .h e definido (implementado) em outro lugar. Isso permite que o compilador inclua informações sobre a assinatura da função (protótipo) para permitir a verificação de tipos de argumentos e corresponder os tipos de retorno a qualquer contexto de chamada em seu código.
Em geral, os arquivos .h (cabeçalho) em C são usados para declarar funções e definir macros.
mkdir
em particular, é uma chamada do sistema. Pode haver um wrapper GNU libc em torno dessa chamada de sistema (quase certamente existe, de fato). A verdadeira implementação do kernelmkdir
pode ser encontrada pesquisando as fontes do kernel e as chamadas do sistema em particular.Observe que também haverá uma implementação de algum tipo de código de criação de diretório para cada sistema de arquivos. A camada VFS (sistema de arquivos virtual) fornece uma API comum na qual a camada de chamada do sistema pode chamar. Todo sistema de arquivos deve registrar funções para a camada VFS chamar. Isso permite que diferentes sistemas de arquivos implementem sua própria semântica de como os diretórios são estruturados (por exemplo, se eles são armazenados usando algum tipo de esquema de hash para tornar mais eficiente a pesquisa de entradas específicas). Menciono isso porque você provavelmente tropeçará nessas funções de criação de diretório específicas do sistema de arquivos se estiver pesquisando na árvore de fontes do kernel Linux.
fonte
Nenhuma das implementações encontradas corresponde ao protótipo em sys / stat.h Talvez a pesquisa de uma instrução de inclusão com esse arquivo de cabeçalho seja mais bem-sucedida?
fonte
Aqui estão algumas ótimas postagens no blog descrevendo várias técnicas para procurar o código-fonte do kernel de baixo nível.
fonte