Crypto Disk Shutdown Problem Workaround (2)
จาก blog ที่แล้ว ที่ได้เขียนถึงการแก้ขัดปัญหา shutdown เครื่อง Debian ที่ใช้ sysvinit ไม่ลง อันเนื่องมาจากการค้างที่ขั้นตอนการปิด crypto disk ด้วยการไปแก้ไฟล์ /lib/cryptsetup/cryptdisks.functions
นั้น หลังจากนั้นก็ได้ครุ่นคิดหาวิธีที่เหมาะสมกว่านั้น จนถึงจุดที่คิดว่าน่าจะลองเสนอใน Debian ได้
ปัญหาของการแก้แบบเดิมก็คือ:
- ไม่ idempotent เพราะใน
do_stop()
ไป stop ดีมอน แต่ในdo_start()
ไม่ได้สั่ง start ดีมอนใหม่ เพราะสมมุติว่ามันถูก start มาแล้ว และทำแค่หา PID ของดีมอนมาใส่ใน omit file เท่านั้น ซึ่งจะทำให้เกิดปัญหาดีมอนตายได้หากผู้ใช้สั่ง stop, start หรือ restart cryptdisks ขณะที่เครื่องทำงานอยู่ ไม่ใช่ผ่านการ shutdown หรือ reboot ตามปกติ - อาจกระทบผู้ใช้ init ระบบอื่น เพราะฟังก์ชันนี้อาจถูกเรียกใช้จากระบบ init อื่นก็ได้ ทั้งที่ระบบเหล่านั้นอาจไม่ได้มีปัญหานี้ และอาจเกิดผลกระทบไม่พึงประสงค์ได้
- ไม่สวยและไม่ปลอดภัย การอ่านค่า PID ด้วย
ps
,grep
,awk
ดูเยิ่นเย้อและไม่ปลอดภัย เพราะawk
อยู่ใน/usr/bin
ซึ่งเสี่ยงต่อการเรียกในระหว่างการบูตที่อาจจะยังมีแค่/bin
หรือ/sbin
ให้ใช้
ปัญหาการกระทบระบบ init อื่น ทำให้มองไปที่การแก้ /etc/init.d/*
แทน ซึ่งในอีกแง่หนึ่ง ก็เป็นการแก้ในระดับบนซึ่งเป็นระดับเดียวกับที่ service อื่น ๆ ใช้จัดการกับ sendsigs อยู่แล้ว จึงสรุปว่าน่าจะเหมาะสมด้วยประการทั้งปวง
เบื้องต้นผมจึงไปแก้ที่ /etc/init.d/cryptdisks
โดยทำหลังจาก do_start
เสร็จแล้ว:
--- /etc/init.d/cryptdisks.orig 2016-10-08 17:14:02.087652932 +0700 +++ /etc/init.d/cryptdisks 2016-10-10 09:42:15.301303974 +0700 @@ -31,9 +31,19 @@ ;; esac +UDEVD_DAEMON="/lib/systemd/systemd-udevd" + case "$1" in start) do_start + + # Omit udev daemon on halt to allow cryptsetup to do the close + UDEVD_PID=$(pidof $UDEVD_DAEMON) + if [ ! -z "$UDEVD_PID" ]; then + OMITDIR=/run/sendsigs.omit.d + mkdir -p $OMITDIR + echo $UDEVD_PID > $OMITDIR/systemd-udevd + fi ;; stop) do_stop
สังเกตว่าในรอบนี้ผมไม่ได้สั่ง stop ดีมอนหลัง do_stop
อีกแล้ว เพราะทำให้เกิดปัญหาไม่ idempotent ดังที่กล่าวไปแล้ว อีกทั้งมันไม่จำเป็นเลย เพราะ service script ของ udev เองก็จะทำหน้าที่ stop ดีมอนนี้ให้อยู่แล้ว สิ่งที่จำเป็นมีแค่ชะลอไม่ให้ดีมอนถูกฆ่าจนถึงตอนนั้นก็พอ
และสังเกตว่าผมไม่ได้ใช้สคริปต์เยิ่นเย้อในการหา PID ของดีมอนอีกแล้ว ในเมื่อสามารถใช้ /bin/pidof
ที่สั้นกระชับและปลอดภัยกว่า
อย่างไรก็ดี สิ่งที่ยังคาใจอยู่ในขั้นนี้ก็คือ มันควรแก้ที่ udev จะเหมาะสมที่สุดถ้าทำได้ เพราะเป็นเจ้าของดีมอนเอง การแยกตรรกะการละเว้นดีมอนมาไว้ที่ service อื่น ดูไม่สวยเท่าไร
ในรอบที่แล้วผมทำกับ udev ไม่สำเร็จ คาดว่าเป็นเพราะไปแทรกโค้ดที่ลำดับต้น ๆ ตั้งแต่เพิ่งเรียกดีมอนใหม่ ๆ ซึ่ง file system อาจจะยังไม่พร้อม อีกทั้งการเรียกใช้ awk
จาก /usr/bin
ก็ยังสุ่มเสี่ยงมากในระหว่างบูตอีกด้วย
รอบนี้ผมจึงลองใหม่ให้หายคาใจ โดยไปแทรกโค้ดในลำดับท้ายสุด หลังจาก Waiting for /dev to be fully populated...
เสร็จแล้ว:
--- /etc/init.d/udev.orig 2016-10-10 09:40:47.937302585 +0700 +++ /etc/init.d/udev 2016-10-10 09:42:59.701304680 +0700 @@ -203,6 +203,14 @@ else log_action_end_msg 0 'timeout' fi + + # Omit systemd-udevd on halt to allow cryptsetup to do the close + UDEVD_PID=$(pidof $DAEMON) + if [ ! -z "$UDEVD_PID" ]; then + OMITDIR=/run/sendsigs.omit.d + mkdir -p $OMITDIR + echo $UDEVD_PID > $OMITDIR/udev + fi ;; stop)
ตรวจความเรียบร้อยแล้วก็ลองรีบูตเครื่องดู... ผ่าน!
ถึงจุดนี้ ก็เลยคิดว่าควรลองเสนอเข้าบั๊ก Debian #791944 ดู (ข้อความ #103) เพื่อให้ผู้ดูแลพิจารณาตามความเหมาะสม
0 ความเห็น:
แสดงความเห็น (มีการกลั่นกรองสำหรับ blog ที่เก่ากว่า 14 วัน)
<< กลับหน้าแรก