web-dev-qa-db-ja.com

シャットダウン手順の説明

「Linuxのしくみ」という本は、一般的なシャットダウン手順(initシステムに依存しない)は次のようになっていると述べています。

  1. initは、すべてのプロセスにクリーンにシャットダウンするように要求します。
  2. プロセスがしばらくして応答しない場合、initはプロセスを強制終了し、最初にTERMシグナルを試行します。
  3. TERMシグナルが機能しない場合、initはすべてのストラグラーでKILLシグナルを使用します。
  4. システムはシステムファイルを所定の位置にロックし、シャットダウンのために他の準備をします。
  5. システムは、ルート以外のすべてのファイルシステムをアンマウントします。
  6. システムはルートファイルシステム読み取り専用を再マウントします。
  7. システムバッファリングされたすべてのデータをファイルシステムに書き出す同期プログラムを使用します。
  8. 最後のステップは、reboot(2)システムコールで再起動または停止するようにカーネルに指示することです。これは、initまたは再起動、停止、電源オフなどの補助プログラムによって実行できます。

ファイルシステムが読み取り専用の場合、同期はどのようにバッファを書き込むことができますか?

4
Aaron

あなたは驚くべきことです:その順序は意味がありません。本がそれをそのように提示するならば、それはずさんで誤解を招くものです。

ファイルシステムをアンマウントするか、読み取り専用でマウントすると、すべてのデータがディスクに書き込まれます。 umountコマンドまたはmount -o remount,roが戻り、すべてのデータがディスクに書き込まれ、syncは何もする必要がありません。前にsyncを呼び出すのは無意味であり(データはとにかくumount操作によって書き込まれます)、後で呼び出すのは無意味です(何もしません)。

これは、syncbefore unmountingを呼び出さなければならなかった一部の古代Unixシステムでは当てはまらなかったと思います。後でそれを呼び出すことはまだ無意味でした。

ファイルシステムの先を見ると、syncが何かをする場合があります。たとえば、Linuxではsyncにより、RAIDアレイのメタデータがディスクに書き込まれるようになると思います。これは、ファイルシステムに読み取り/書き込みがマウントされていない場合でも役立ちます。

Fs読み取り専用を再マウントすると、ファイルレベルの書き込み要求とrwモードでのopen()呼び出しがプロセスから防止されるため、データとfs構造をさらに変更することはできません。バッファリングはブロックデバイスドライバとfsドライバの間にあるため、システムにダーティバッファがある場合は、基盤となるメディアに書き込む必要があります。

典型的なスタックは次のようになります。

  • 処理する
  • カーネルファイルioAPI
  • fsドライバー、例: ext3fs
  • blkdev抽象化レイヤー、API、いくつかの便利なプリミティブ、デフォルトの動作など。カーネルの一部。また、このレイヤーはバッファーとディスクキャッシュを管理し、カーネルにスワッピングを提供します。
  • ブロックデバイスドライバー、例: scsilinuxサブシステム。
  • ストレージデバイス

さまざまなレベルで可能なループもあります。たとえば、ファイルは、ストレージをバッキングするループデバイス、LUKSデバイス暗号化などとして使用できます。

2
Serge

シャットダウンを実行するコードの一部を次に示します(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);
}

あなたが最初に見ることができるように、プロセスキル部分は次のとおりです。

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);

syncを使用してデータをディスクに書き込みます。次に、スワップをオフにして、すべてのファイルシステムをアンマウントします。その後、実際の停止または再起動が発生します。

Manページからのsyncの説明:

sync()により、ファイルシステムメタデータおよびキャッシュされたファイルデータに対する保留中のすべての変更が、基になるファイルシステムに書き込まれます。

この本は少し古いか、シャットダウンの他の実装を説明している可能性があります。コードとマニュアルページを読むことも、Linuxがどのように機能するかを学ぶための非常に良い方法です。

1
coffeMug