「How Linux Works」という本には、一般的なシャットダウンプロセス(initシステムとは無関係)が次のように記載されています。
- initを実行するには、各プロセスを完全に終了する必要があります。
- 一定時間が経過してもプロセスが応答しない場合、initはプロセスを終了し、TERM信号を最初に試みます。
- TERM信号が無効の場合、initはすべての遅延に対してKILL信号を使用します。
- システムはシステムファイルを所定の位置にロックし、シャットダウンの準備をします。
- システムは、ルートを除くすべてのファイルシステムをアンマウントします。
- システムが再マウントされました。ルートファイルシステム読み取り専用。
- システムバッファリングされたすべてのデータをファイルシステムに書き込む同期手順を通じて
- 最後のステップは、boot(2)システムコールを介してカーネルに再起動または停止を指示することです。これは、初期化、再起動、一時停止、電源オフなどのヘルパープログラムを介して実行できます。
ファイルシステムが読み取り専用の場合、同期はどのようにそのバッファに書き込みを行いますか?
答え1
あなたが驚いたことは正しいです。このコマンドは意味がありません。本にこのような内容が記載されている場合、それは急いで誤解を招くことです。
ファイルシステムをアンマウントまたは読み取り専用でマウントすると、すべてのデータがディスクに書き込まれます。umount
コマンドまたは戻りが実行されると、mount -o remount,ro
すべてのデータがディスクに書き込まれ、sync
これ以上何もしません。以前に呼び出すことは意味がなくsync
(どうせマウント解除操作によってデータが書き込まれて)、その後に呼び出すことは意味がありません(何もしません)。
私はこれがいくつかの古代のUnixシステムでは本当ではないと思います。sync
今後削除。後で電話することはまだ理にかなっていません。
ファイルシステム以上の機能を使用すると、特定の状況でsync
特定のタスクを実行できます。たとえば、Linuxでは、sync
RAIDアレイのメタデータをディスクに書き込むことができると思います。これはファイルシステムを読み書きしなくても便利です。
答え2
fs読み取り専用を再マウントすると、プロセスはrwモードのすべてのファイルレベルの書き込み要求とopen()呼び出しをブロックし、データ構造とfs構造を変更できなくなります。バッファリングはブロックデバイスドライバとファイルシステムドライバの間にあるため、システムにダーティバッファがある場合はプライマリメディアに書き込む必要があります。
一般的なスタックは次のとおりです。
- プロセス
- カーネルファイルio API
fs
ドライバの例:ext3fs
blkdev
コア、抽象化レイヤ、API、多くの有用な基本要素、基本的な動作などの一部です。さらに、この層はバッファとディスクキャッシュを管理し、カーネルとの交換を提供します。scsi
Linuxサブシステムなどのデバイスドライバをブロックします。- ストレージデバイス
ループは様々なレベルに存在することもできる。たとえば、ファイルをループデバイスとして使用して、ストレージ、LUKS
デバイス暗号化などをサポートできます。
答え3
以下は、シャットダウンを実行するコードの一部です(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
。その後、スワップを閉じて、すべてのファイルシステムをアンマウントします。その後、実際の停止または再起動が発生します。
sync
マニュアルページの説明:
sync() は、ファイルシステムのメタデータとキャッシュされたファイルデータに対して保留中のすべての変更をデフォルトのファイルシステムに書き込むことを可能にします。
この本は少し古くなったり、他のクロージャの実装を説明したりできます。コードとマニュアルページを読むこともLinuxの仕組みを学ぶための良い方法です。