「Linuxのしくみ」という本は、一般的なシャットダウン手順(initシステムに依存しない)は次のようになっていると述べています。
ファイルシステムが読み取り専用の場合、同期はどのようにバッファを書き込むことができますか?
あなたは驚くべきことです:その順序は意味がありません。本がそれをそのように提示するならば、それはずさんで誤解を招くものです。
ファイルシステムをアンマウントするか、読み取り専用でマウントすると、すべてのデータがディスクに書き込まれます。 umount
コマンドまたはmount -o remount,ro
が戻り、すべてのデータがディスクに書き込まれ、sync
は何もする必要がありません。前にsync
を呼び出すのは無意味であり(データはとにかくumount操作によって書き込まれます)、後で呼び出すのは無意味です(何もしません)。
これは、sync
before unmountingを呼び出さなければならなかった一部の古代Unixシステムでは当てはまらなかったと思います。後でそれを呼び出すことはまだ無意味でした。
ファイルシステムの先を見ると、sync
が何かをする場合があります。たとえば、Linuxではsync
により、RAIDアレイのメタデータがディスクに書き込まれるようになると思います。これは、ファイルシステムに読み取り/書き込みがマウントされていない場合でも役立ちます。
Fs読み取り専用を再マウントすると、ファイルレベルの書き込み要求とrwモードでのopen()呼び出しがプロセスから防止されるため、データとfs構造をさらに変更することはできません。バッファリングはブロックデバイスドライバとfsドライバの間にあるため、システムにダーティバッファがある場合は、基盤となるメディアに書き込む必要があります。
典型的なスタックは次のようになります。
fs
ドライバー、例: ext3fs
blkdev
抽象化レイヤー、API、いくつかの便利なプリミティブ、デフォルトの動作など。カーネルの一部。また、このレイヤーはバッファーとディスクキャッシュを管理し、カーネルにスワッピングを提供します。scsi
linuxサブシステム。さまざまなレベルで可能なループもあります。たとえば、ファイルは、ストレージをバッキングするループデバイス、LUKS
デバイス暗号化などとして使用できます。
シャットダウンを実行するコードの一部を次に示します(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がどのように機能するかを学ぶための非常に良い方法です。