Como posso encontrar as implementações das chamadas do sistema kernel do Linux?

372

Estou tentando entender como uma função, digamos mkdir , funciona observando a origem 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 preciso ver em qual arquivo C esta função está implementada. No diretório de origem, tentei

ack "int mkdir"

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 .

Perguntas

  1. Qual arquivo tem a implementação mkdir ?
  2. 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 .

    
por Navaneeth K N 19.08.2010 / 16:26

7 respostas

386

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 assembly embutido injetado em 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.

Em include/linux/syscalls.h sob o diretório fonte do seu kernel, você encontra isto:

asmlinkage long sys_mkdir(const char __user *pathname, int mode);

Então, em /usr/include/asm*/unistd.h , você encontra isto:

#define __NR_mkdir                              83
__SYSCALL(__NR_mkdir, sys_mkdir)

Este código está dizendo mkdir(2) é a chamada do sistema # 83. Ou seja, as chamadas do sistema são chamadas por número, não por endereço como em uma chamada de função normal dentro de seu próprio programa ou por uma função em uma biblioteca vinculada ao seu programa. O código de cola de montagem inline que eu mencionei acima usa isso para fazer a transição do usuário para o espaço do kernel, levando seus parâmetros junto com ele.

Outra pequena evidência de que as coisas são um pouco estranhas aqui é que nem sempre há uma lista de parâmetros rígidos para as chamadas do sistema: open(2) , por exemplo, pode ter 2 ou 3 parâmetros. Isso significa que open(2) é sobrecarregado , um recurso do C ++, não do C, mas a interface syscall é compatível com o C. (Isso não é a mesma coisa que o recurso varargs do C , que permite que uma única função obtenha um número variável de argumentos.)

Para responder à sua primeira pergunta, não há um único arquivo em que 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 ao kernel esconder tudo o que está por trás de uma única chamada de sistema é chamada de VFS . Então, você provavelmente quer começar a pesquisar em fs/namei.c , com vfs_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 do ext4 é chamada ext4_mkdir() , definida em fs/ext4/namei.c .

Quanto à sua segunda pergunta, sim, há padrões para tudo isso, mas não uma regra única. O que você realmente precisa é de um entendimento bastante amplo de como o kernel funciona para descobrir onde você deve procurar qualquer chamada de sistema específica. Nem todas as chamadas de sistema envolvem o VFS, portanto, suas cadeias de chamadas do lado do kernel não são todas iniciadas em fs/namei.c . mmap(2) , por exemplo, começa em mm/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.

    
por 19.08.2010 / 17:28
83

Isso provavelmente não responde à sua pergunta diretamente, mas achei strace muito legal ao tentar entender as chamadas de sistema subjacentes, em ação, feitas até para os comandos de shell mais simples. por exemplo,

strace -o trace.txt mkdir mynewdir

O sistema pede que o comando mkdir mynewdir seja enviado para o trace.txt para o seu prazer de visualização.

    
por 19.08.2010 / 21:37
54

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, portanto, é mais prático 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 o nome mutilado pelo pré-processador em todo o lugar. No entanto, a maioria das chamadas do sistema (todas?) É definida com um dos SYSCALL_DEFINEx famílias de macros. Como mkdir recebe dois argumentos, uma pesquisa por SYSCALL_DEFINE2(mkdir leva ao declaração do mkdir syscall :

SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
{
    return sys_mkdirat(AT_FDCWD, pathname, mode);
}

ok, sys_mkdirat significa que é o mkdirat syscall, então clicar nele só leva você à declaração em include/linux/syscalls.h , mas a definição é logo acima.

A tarefa principal de mkdirat é chamar vfs_mkdir (VFS é a camada genérica do sistema de arquivos). Clicando em que mostra dois resultados da pesquisa: a declaração em include/linux/fs.h , ea definição de algumas linhas acima. A tarefa principal de vfs_mkdir é chamar a implementação específica do sistema de arquivos: dir->i_op->mkdir . Para descobrir como isso é implementado, você precisa ativar a implementação do sistema de arquivos individual, e não há nenhuma regra de hard-and-fast - pode até ser um módulo fora da árvore do kernel.

¹ O 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 web ligeiramente diferentes. Eles tendem a ir e vir, então se o que você está acostumado não estiver disponível, faça uma busca na web por “referência cruzada de linux” para encontrar outro.

    
por 04.01.2011 / 22:09
21

As chamadas do sistema geralmente são agrupadas na macro SYSCALL_DEFINEx() , e é por isso que um simples grep não as encontra:

fs/namei.c:SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)

O nome final da função depois que a macro é expandida acaba sendo sys_mkdir . A macro SYSCALL_DEFINEx() adiciona elementos padrão como código de rastreamento que cada definição syscall precisa ter.

    
por 20.08.2010 / 08:16
17

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 é, na verdade). A verdadeira implementação do kernel de mkdir pode ser encontrada pesquisando as fontes do kernel e as chamadas do sistema em particular.

Note 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 (virtual filesystem) 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. 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 hashing para tornar a busca por entradas específicas mais eficiente). Eu mencionei isso porque você provavelmente tropeçará nessas funções de criação de diretórios específicos do sistema de arquivos se estiver pesquisando na árvore de fontes do kernel do Linux.

    
por 21.08.2010 / 09:31
8

Nenhuma das implementações encontradas corresponde ao protótipo em sys / stat.h Talvez a pesquisa por uma instrução include com esse arquivo de cabeçalho seja mais bem-sucedida?

    
por 19.08.2010 / 17:19
6

Aqui estão algumas ótimas postagens de blog descrevendo várias técnicas para caçar o código fonte do kernel de baixo nível.

por 13.01.2011 / 23:04