Clarificação do procedimento de encerramento

4

O livro "Como o Linux funciona" diz que o procedimento geral de desligamento (independente do sistema init) é algo assim:

    O
  1. init solicita que todos os processos sejam encerrados de forma limpa.
  2. Se um processo não responder depois de um tempo, o init o mata, primeiro tentando um sinal TERM.
  3. Se o sinal TERM não funcionar, o init usa o sinal KILL em qualquer um deles.
  4. O sistema bloqueia os arquivos do sistema e faz outras preparações para o encerramento.
  5. O sistema desmonta todos os sistemas de arquivos que não sejam a raiz.
  6. O sistema remonta o sistema de arquivos raiz somente leitura .
  7. O sistema grava todos os dados em buffer no sistema de arquivos com o programa de sincronização.
  8. O passo final é dizer ao kernel para reiniciar ou parar com a chamada de sistema de reinicialização (2). Isso pode ser feito pelo init ou por um programa auxiliar, como reinicialização, interrupção ou desligamento.

Como pode sincronizar seus buffers se o sistema de arquivos for somente leitura?

    
por Aaron 31.05.2016 / 22:39

3 respostas

4

Você está certo em se surpreender: essa ordem não faz sentido. Se um livro apresenta dessa forma, é desleixado e enganoso.

Desmontando um sistema de arquivos ou montando-o somente leitura, grava todos os dados no disco. Quando o comando umount ou mount -o remount,ro retornar, todos os dados serão gravados no disco e sync não terá mais nada a fazer. É inútil chamar sync antes (os dados serão gravados pela operação de umount de qualquer maneira) e inútil chamar depois (não fará nada).

Eu acho que isso não era verdade em alguns antigos sistemas Unix, onde você tinha que chamar sync antes de desmontar. Chamá-lo depois ainda era inútil.

Se você olhar além dos sistemas de arquivos, pode haver casos em que sync faça alguma coisa. Por exemplo, acho que no Linux sync garante que os metadados dos arrays RAID sejam gravados no disco. Isso é útil mesmo na ausência de qualquer leitura / gravação montada no sistema de arquivos.

    
por 01.06.2016 / 01:36
2

A remontagem de um fs read impede qualquer pedido de gravação em nível de arquivo e chamadas open () com o modo rw dos processos, portanto, nenhum outro dado e modificação da estrutura do fs é possível. O buffer é colocado entre os drivers de dispositivo de bloco e os drivers de fs, portanto, se o sistema tiver algum buffer sujo, ele deverá gravá-los na mídia subjacente.

A pilha típica parece assim:

  • processo
  • API io do arquivo de kernel
  • fs driver, por ex. %código%
  • ext3fs abstraction layer, uma API, várias primitivas úteis, comportamentos padrão, e.t.c. parte do kernel. Além disso, esta camada gerencia buffers e caches de disco, além de fornecer swap ao kernel.
  • bloquear driver de dispositivo, por exemplo blkdev subsistema linux.
  • dispositivo de armazenamento

Também há loops possíveis em diferentes níveis. Por exemplo, um arquivo pode ser usado como um armazenamento de apoio de dispositivo de loop, scsi device encryption, e.t.c.

    
por 01.06.2016 / 00:10
1

Aqui está parte do código que faz o desligamento (implementação do estilo System V):

/*
 *  Kill all processes, call /etc/init.d/halt (if present)
 */
void fastdown()
{
    int do_halt = (down_level[0] == '0');
    int i;
#if 0
    char cmd[128];
    char *script;

    /*
     *  Currently, the halt script is either init.d/halt OR rc.d/rc.0,
     *  likewise for the reboot script. Test for the presence
     *  of either.
     */
    if (do_halt) {
        if (access(HALTSCRIPT1, X_OK) == 0)
            script = HALTSCRIPT1;
        else
            script = HALTSCRIPT2;
    } else {
        if (access(REBOOTSCRIPT1, X_OK) == 0)
            script = REBOOTSCRIPT1;
        else
            script = REBOOTSCRIPT2;
    }
#endif

    /* First close all files. */
    for(i = 0; i < 3; i++)
        if (!isatty(i)) {
            close(i);
            open("/dev/null", O_RDWR);
        }
    for(i = 3; i < 20; i++) close(i);
    close(255);

    /* First idle init. */
    if (kill(1, SIGTSTP) < 0) {
        fprintf(stderr, "shutdown: can't idle init: %s.\r\n", strerror(errno));
        exit(1);
    }

    /* Kill all processes. */ 
    fprintf(stderr, "shutdown: sending all processes the TERM signal...\r\n");
    kill(-1, SIGTERM);
    sleep(sltime ? atoi(sltime) : 3);
    fprintf(stderr, "shutdown: sending all processes the KILL signal.\r\n");
    (void) kill(-1, SIGKILL);

#if 0
    /* See if we can run /etc/init.d/halt */
    if (access(script, X_OK) == 0) {
        spawn(1, cmd, "fast", NULL);
        fprintf(stderr, "shutdown: %s returned - falling back "
                "on default routines\r\n", script);
    }
#endif

    /* script failed or not present: do it ourself. */
    sleep(1); /* Give init the chance to collect zombies. */

    /* Record the fact that we're going down */
    write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");

    /* This is for those who have quota installed. */
#if defined(ACCTON_OFF)
# if (ACCTON_OFF > 1) && (_BSD_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500))
    /* This is an alternative way to disable accounting, saving a fork() */
    if (acct(NULL))
        fprintf(stderr, "shutdown: can not stop process accounting: %s.\r\n", strerror(errno));
# elif (ACCTON_OFF > 0)
    spawn(1, "accton", "off", NULL);
# else
    spawn(1, "accton", NULL);
# endif
#endif
    spawn(1, "quotaoff", "-a", NULL);

    sync();
    fprintf(stderr, "shutdown: turning off swap\r\n");
    spawn(0, "swapoff", "-a", NULL);
    fprintf(stderr, "shutdown: unmounting all file systems\r\n");
    spawn(0, "umount", "-a", NULL);

    /* We're done, halt or reboot now. */
    if (do_halt) {
        fprintf(stderr, "The system is halted. Press CTRL-ALT-DEL "
                "or turn off power\r\n");
        init_reboot(BMAGIC_HALT);
        exit(0);
    }

    fprintf(stderr, "Please stand by while rebooting the system.\r\n");
    init_reboot(BMAGIC_REBOOT);
    exit(0);
}

Como você pode ver primeiro a parte de kill do processo é, então nós temos:

sync();
fprintf(stderr, "shutdown: turning off swap\r\n");
spawn(0, "swapoff", "-a", NULL);
fprintf(stderr, "shutdown: unmounting all file systems\r\n");
spawn(0, "umount", "-a", NULL);

Que grava os dados no disco usando sync . Em seguida, desativa a troca e desmonta todos os sistemas de arquivos. Então parada ou reinicialização real acontece.

Descrição de sync da página man:

sync() causes all pending modifications to file system metadata and cached file data to be written to the underlying filesystems.

O livro pode ser um pouco antigo ou explicar outra implementação do desligamento. Ler o código e as man pages também é uma ótima maneira de aprender como o Linux funciona.

    
por 01.06.2016 / 12:30