ti-enxame.com

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

Eu estou tentando entender como uma função, digamos mkdir, funciona olhando 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.

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 .

376
Navaneeth K N

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 do código do Assembly 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.

Em include/linux/syscalls.h no diretório de origem do kernel, você encontra o seguinte:

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

Em /usr/include/asm*/unistd.h, Você encontra o seguinte:

#define __NR_mkdir                              83
__SYSCALL(__NR_mkdir, sys_mkdir)

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 embutido que mencionei acima usa isso para fazer a transição do espaço do usuário para o kernel, levando seus parâmetros junto.

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 aceitar 2 ou 3 parâmetros. Isso significa que open(2) é sobrecarregado , um recurso do C++, não C, mas a interface do syscall é compatível com o C. (Isso não é o mesmo que C's recurso varargs , 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 VFS . Então, você provavelmente quer começar a digitar 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 ext4 é chamada ext4_mkdir(), definida em fs/ext4/namei.c .

Quanto à sua segunda pergunta, sim, existem padrões para tudo isso, mas nenhuma regra. O que você realmente precisa é de uma compreensão bastante ampla 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, suas cadeias de chamadas do lado do kernel nem todas começam 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 Linux Kernel " de Bovet e Cesati.

388
Warren Young

Provavelmente, isso não responde diretamente à sua pergunta, mas achei strace muito interessante ao tentar entender as chamadas subjacentes do sistema, em ação, feitas até para os comandos mais simples do Shell. por exemplo.

strace -o trace.txt mkdir mynewdir

O sistema chama pelo comando mkdir mynewdir será transferido para trace.txt para o seu prazer.

86
Banjer

Um bom lugar para ler a fonte do kernel 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 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 (todas?) Do sistema é definida com um dos SYSCALL_DEFINEx famílias de macros. Como mkdir usa dois argumentos, uma pesquisa por SYSCALL_DEFINE2(mkdir leva à declaração do mkdir syscall :

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

está bem, sys_mkdirat significa que é o syscall mkdirat, portanto, clicar nele leva apenas à declaração em include/linux/syscalls.h, mas a definição está logo acima.

A principal tarefa de mkdirat é chamar vfs_mkdir (VFS é a camada genérica do sistema de arquivos). Clique aqui para mostrar dois resultados de pesquisa: a declaração em include/linux/fs.h, e a definição algumas linhas acima. O trabalho principal de vfs_mkdir é chamar a implementação específica do sistema de arquivos: dir->i_op->mkdir. Para descobrir como isto é implementado, você precisa recorrer à implementação do sistema de arquivos individual e não há 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.

56

As chamadas do sistema geralmente são agrupadas na macro SYSCALL_DEFINEx(), razão pela qual um simples grep não as encontra:

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

O nome da função final após a expansão da macro acaba sendo sys_mkdir. A macro SYSCALL_DEFINEx() adiciona itens padrão, como código de rastreamento que cada definição de syscall precisa ter.

22
stefanha

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 tipo de argumentos e corresponder os tipos de retorno a qualquer contexto de chamada no 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 GNU libc wrapper em torno dessa chamada do sistema (quase certamente é, de fato).) A verdadeira implementação do kernel de mkdir pode ser encontrada pesquisando as fontes do kernel e o sistema chama 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.

17
Jim Dennis

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?

8
greg0ire

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.

6
An̲̳̳drew