ทำไมมีนโยบายเคอร์เนลของ Linux ที่จะไม่ทำลายพื้นที่ผู้ใช้?


38

ฉันเริ่มคิดถึงปัญหานี้ในบริบทของมารยาทในลิสต์การส่งเมลเคอร์เนล ในฐานะที่เป็นโครงการซอฟท์แวร์ฟรีที่เป็นที่รู้จักและประสบความสำเร็จมากที่สุดในโลกลินุกซ์เคอร์เนลจึงได้รับความนิยม และผู้ก่อตั้งและผู้นำโครงการ Linus Torvalds ไม่ต้องการคำแนะนำที่นี่อย่างชัดเจน

ไลนัสดึงดูดความขัดแย้งกับเปลวไฟบน LKML เป็นครั้งคราว เปลวไฟเหล่านี้เกิดขึ้นบ่อยครั้งโดยการยอมรับของเขาเองที่เกี่ยวข้องกับการแบ่งพื้นที่ผู้ใช้ ซึ่งนำมาสู่คำถามของฉัน

ฉันสามารถมีมุมมองทางประวัติศาสตร์เกี่ยวกับสาเหตุที่ทำให้การแบ่งพื้นที่ผู้ใช้เป็นเรื่องเลวร้ายได้หรือไม่ ตามที่ฉันเข้าใจแล้วการแบ่งพื้นที่ของผู้ใช้จะต้องมีการแก้ไขในระดับแอปพลิเคชัน แต่นี่เป็นสิ่งที่ไม่ดีถ้ามันปรับปรุงรหัสเคอร์เนล

ตามที่ฉันเข้าใจแล้วนโยบายที่ระบุไว้ของ Linus คือการไม่ทำลายพื้นที่ของผู้ใช้ทำให้สำคัญกว่าทุกอย่างรวมถึงคุณภาพของรหัส เหตุใดสิ่งนี้จึงสำคัญและข้อดีและข้อเสียของนโยบายดังกล่าวคืออะไร

(เห็นได้ชัดว่ามีข้อเสียบางประการเกี่ยวกับนโยบายดังกล่าวซึ่งมีการนำมาใช้อย่างสม่ำเสมอเนื่องจากบางครั้งไลนัสมี "ความไม่เห็นด้วย" กับผู้แทนระดับสูงของ LKML ในหัวข้อนี้อย่างแน่นอนเท่าที่ฉันสามารถบอกได้


1
คุณสะกดชื่อ Linus ผิดในบทนำ
Ismael Miguel

ไม่ใช่ฉันอย่างแน่นอน แต่ฉันลืมที่จะ upvote และให้คะแนนของฉันตอนนี้
Ismael Miguel

1
ที่เกี่ยวข้อง: stackoverflow.com/q/25954270/350713
Faheem Mitha

คำตอบ:


38

เหตุผลไม่ใช่เหตุผลเชิงประวัติศาสตร์ แต่เป็นเหตุผลเชิงปฏิบัติ มีหลายโปรแกรมมากมายที่รันบนเคอร์เนล Linux; ถ้าส่วนต่อประสานเคอร์เนลทำลายโปรแกรมเหล่านั้นทุกคนจะต้องอัพเกรดโปรแกรมเหล่านั้น

ตอนนี้มันเป็นความจริงที่โปรแกรมส่วนใหญ่ไม่ได้ขึ้นอยู่กับอินเทอร์เฟซของเคอร์เนลโดยตรง (การเรียกของระบบ ) แต่ขึ้นอยู่กับอินเตอร์เฟสของไลบรารีมาตรฐาน C (ตัวห่อ C รอบการเรียกระบบ) โอ้ แต่ห้องสมุดมาตรฐานอะไร glibc? uClibc? Dietlibc? ไบโอนิค? คิดถึง? เป็นต้น

แต่ก็มีหลายโปรแกรมที่ใช้บริการเฉพาะระบบปฏิบัติการและขึ้นอยู่กับอินเตอร์เฟสของเคอร์เนลที่ไม่ได้เปิดเผยโดยไลบรารีมาตรฐาน (บนลินุกซ์หลายเหล่านี้ถูกนำเสนอผ่าน/procและ/sys.)

จากนั้นก็จะมีการรวบรวมไบนารีแบบคงที่ หากการอัพเกรดเคอร์เนลแตกหนึ่งในนั้นทางออกเดียวเท่านั้นที่จะคอมไพล์ใหม่ หากคุณมีแหล่งที่มา: Linux จะสนับสนุนซอฟต์แวร์ที่เป็นกรรมสิทธิ์ด้วย

แม้ว่าจะมีแหล่งที่มา แต่ก็รวบรวมได้ทั้งหมดอาจเจ็บปวด โดยเฉพาะอย่างยิ่งเมื่อคุณอัพเกรดเคอร์เนลเพื่อแก้ไขข้อบกพร่องด้วยฮาร์ดแวร์ของคุณ ผู้คนมักจะอัพเกรดเคอร์เนลเป็นอิสระจากระบบอื่น ๆ เพราะพวกเขาต้องการการสนับสนุนฮาร์ดแวร์ ในคำพูดของ Linus Torvalds :

การทำลายโปรแกรมผู้ใช้ไม่สามารถทำได้ (…) เรารู้ว่าผู้คนใช้ไบนารีเก่ามานานหลายปีและการสร้างรุ่นใหม่ไม่ได้หมายความว่าคุณจะสามารถกำจัดทิ้งได้ คุณสามารถไว้วางใจเรา

นอกจากนี้เขายังอธิบายด้วยว่าเหตุผลหนึ่งที่ทำให้กฎข้อนี้แข็งแกร่งคือการหลีกเลี่ยงการพึ่งพานรกซึ่งคุณไม่เพียง แต่ต้องอัพเกรดโปรแกรมอื่นเพื่อให้เคอร์เนลใหม่บางตัวทำงาน แต่ยังต้องอัพเกรดอีกโปรแกรมหนึ่งและอีกอันและอีกอันหนึ่ง เพราะทุกอย่างขึ้นอยู่กับรุ่นทุกอย่าง

มันค่อนข้างโอเคที่จะมีการพึ่งพาทางเดียวที่กำหนดไว้อย่างดี มันเศร้า แต่ก็หลีกเลี่ยงไม่ได้บางครั้ง (…) สิ่งที่ไม่เป็นไรคือการพึ่งพาสองทาง หากรหัสพื้นที่ผู้ใช้ HAL ขึ้นอยู่กับเคอร์เนลใหม่ก็โอเคแม้ว่าฉันสงสัยว่าผู้ใช้จะหวังว่ามันจะไม่เป็น "เคอร์เนลของสัปดาห์" แต่สิ่งที่ "เคอร์เนลของไม่กี่เดือนที่ผ่านมา"

แต่ถ้าคุณมีการพึ่งพาแบบสองทางคุณจะเมา นั่นหมายความว่าคุณต้องอัพเกรดในขั้นตอนการล็อคและนั่นก็ไม่ได้รับการยอมรับ มันเป็นเรื่องที่น่ากลัวสำหรับผู้ใช้ แต่ที่สำคัญยิ่งกว่านั้นก็เป็นเรื่องที่น่ากลัวสำหรับนักพัฒนาเพราะนั่นหมายความว่าคุณไม่สามารถพูดว่า "มีข้อผิดพลาดเกิดขึ้น" และทำสิ่งต่าง ๆ เช่นพยายาม จำกัด ให้แคบลง

ใน userspace การพึ่งพาซึ่งกันและกันเหล่านั้นมักจะถูกแก้ไขโดยทำให้ไลบรารีต่าง ๆ แต่คุณจะเรียกใช้เพียงหนึ่งเคอร์เนลดังนั้นจึงต้องสนับสนุนทุกสิ่งที่ผู้คนอาจต้องการทำกับมัน

อย่างเป็นทางการ ,

ความเข้ากันได้แบบย้อนหลังสำหรับ [สายระบบประกาศมั่นคง] จะรับประกันอย่างน้อย 2 ปี

ในทางปฏิบัติแม้ว่า

อินเทอร์เฟซส่วนใหญ่ (เช่น syscalls) คาดว่าจะไม่มีการเปลี่ยนแปลงและพร้อมใช้งานเสมอ

สิ่งที่เปลี่ยนแปลงบ่อยขึ้นคืออินเทอร์เฟซที่ใช้สำหรับโปรแกรมที่เกี่ยวข้องกับฮาร์ดแวร์/sysเท่านั้น ( /procในทางกลับกันซึ่งนับตั้งแต่การเปิดตัว/sysถูกสงวนไว้สำหรับบริการที่ไม่เกี่ยวข้องกับฮาร์ดแวร์มันค่อนข้างจะไม่เข้ากันได้ในทางที่ไม่เข้ากัน)

สรุป,

การแบ่งพื้นที่ผู้ใช้จะต้องมีการแก้ไขในระดับแอปพลิเคชัน

และนั่นก็ไม่ดีเพราะมีเพียงเคอร์เนลเดียวซึ่งผู้คนต้องการอัพเกรดโดยไม่ขึ้นกับส่วนที่เหลือของระบบ แต่ก็มีแอพพลิเคชั่นมากมายที่มีการพึ่งพาซึ่งกันและกัน มันง่ายกว่าที่จะรักษาเสถียรภาพของเคอร์เนลที่จะทำให้แอพพลิเคชั่นนับพันเป็นปัจจุบันในการตั้งค่าต่างๆ


1
ขอบคุณสำหรับคำตอบ ดังนั้นอินเทอร์เฟซที่ได้รับการประกาศว่ามีความเสถียรนั้นเป็น superset ของการเรียกระบบ POSIX หรือไม่? คำถามของฉันเกี่ยวกับประวัติความเป็นมาของการปฏิบัตินี้วิวัฒนาการ สันนิษฐานว่า Linux kernel รุ่นดั้งเดิมไม่ต้องกังวลเกี่ยวกับการแตกพื้นที่ของผู้ใช้อย่างน้อยในตอนแรก
Faheem Mitha

3
@FaheemMitha ใช่พวกเขาตั้งแต่ปี 1991 ฉันไม่คิดว่าวิธีการของไลนัสจะได้รับการพัฒนามันเป็น“ อินเทอร์เฟซสำหรับแอปพลิเคชันทั่วไปไม่เปลี่ยนแปลงอินเทอร์เฟซสำหรับซอฟต์แวร์ที่เชื่อมโยงกับเคอร์เนลเปลี่ยนไปอย่างมากน้อยมาก”
Gilles 'หยุดความชั่วร้าย'

24

ในระบบการพึ่งพาระหว่างกันนั้นมีสองตัวเลือก สิ่งที่เป็นนามธรรมและบูรณาการ (ฉันตั้งใจจะไม่ใช้คำศัพท์ทางเทคนิค) ด้วย Abstraction คุณกำลังบอกว่าเมื่อคุณโทรไปยัง API นั้นในขณะที่โค้ดที่อยู่หลัง API อาจเปลี่ยนไปผลลัพธ์จะเหมือนเดิมเสมอ ตัวอย่างเช่นเมื่อเราโทรหาfs.open()เราไม่สนใจว่าเป็นไดรฟ์เครือข่าย SSD หรือฮาร์ดไดรฟ์เราจะได้รับตัวอธิบายไฟล์แบบเปิดที่เราสามารถทำสิ่งต่างๆได้เสมอ ด้วย "การบูรณาการ" เป้าหมายคือเพื่อให้วิธีที่ "ดีที่สุด" ในการทำสิ่งใดแม้ว่าวิธีการเปลี่ยนแปลง ตัวอย่างเช่นการเปิดไฟล์อาจแตกต่างกันไปสำหรับเครือข่ายที่ใช้ร่วมกันกว่าสำหรับไฟล์บนดิสก์ ทั้งสองวิธีนี้ถูกใช้อย่างกว้างขวางในเดสก์ท็อป Linux ที่ทันสมัย

จากมุมมองของนักพัฒนามันเป็นคำถามของ "ใช้งานได้กับทุกรุ่น" หรือ "ใช้งานได้กับรุ่นเฉพาะ" ตัวอย่างที่ดีของเรื่องนี้คือ OpenGL เกมส่วนใหญ่ถูกตั้งค่าให้ทำงานกับ OpenGL รุ่นที่เฉพาะเจาะจง ไม่สำคัญว่าคุณกำลังรวบรวมจากแหล่งที่มาหรือไม่ หากเกมนั้นเขียนขึ้นเพื่อใช้ OpenGL 1.1 และคุณกำลังพยายามทำให้เกมรันบน 3.x คุณจะไม่ได้มีช่วงเวลาที่ดี อีกด้านหนึ่งของคลื่นความถี่บางสายคาดว่าจะทำงานไม่ว่าจะเกิดอะไรขึ้น ตัวอย่างเช่นฉันต้องการโทรหาfs.open()ฉันไม่ต้องการให้สนใจว่าฉันใช้เคอร์เนลเวอร์ชันใด ฉันแค่ต้องการไฟล์อธิบาย

มีประโยชน์กับแต่ละทาง การรวมให้คุณสมบัติ "ใหม่กว่า" ด้วยค่าใช้จ่ายในการใช้งานร่วมกันได้ ในขณะที่สิ่งที่เป็นนามธรรมให้ความมั่นคงในการโทร "ใหม่" แม้ว่าจะเป็นสิ่งสำคัญที่จะต้องทราบว่าเป็นเรื่องของลำดับความสำคัญไม่ใช่ความเป็นไปได้

จากจุดยืนของชุมชนโดยไม่มีเหตุผลที่ดีจริง ๆ สิ่งที่เป็นนามธรรมนั้นดีกว่าในระบบที่ซับซ้อนเสมอ ตัวอย่างเช่นสมมติว่าfs.open()ทำงานแตกต่างกันไปตามรุ่นของเคอร์เนล จากนั้นไลบรารีการโต้ตอบของระบบไฟล์อย่างง่ายจะต้องรักษาวิธี "open file" ที่แตกต่างกันหลายร้อยวิธี (หรือบล็อกอาจ) เมื่อเคอร์เนลเวอร์ชันใหม่ออกมาคุณจะไม่สามารถ "อัปเกรด" คุณจะต้องทดสอบซอฟต์แวร์ทุกชิ้นที่คุณใช้ เคอร์เนล 6.2.2 (ปลอม) อาจทำลายโปรแกรมแก้ไขข้อความของคุณ

สำหรับตัวอย่างในโลกแห่งความเป็นจริง OSX มีแนวโน้มที่จะไม่สนใจเรื่องการแบ่งพื้นที่ผู้ใช้ พวกเขาตั้งเป้าหมายที่จะ "รวม" มากกว่า "นามธรรม" บ่อยครั้งมากขึ้น และในทุก ๆ การอัพเดทหลัก ๆ นั่นไม่ได้หมายความว่าจะดีกว่าอีกวิธีหนึ่ง มันเป็นทางเลือกและการตัดสินใจออกแบบ

สิ่งสำคัญที่สุดคือระบบนิเวศของ Linux เต็มไปด้วยโครงการโอเพนซอร์สที่ยอดเยี่ยมซึ่งผู้คนหรือกลุ่มทำงานในโครงการในเวลาว่างหรือเพราะเครื่องมือนี้มีประโยชน์ เมื่อคำนึงถึงสิ่งที่สองมันหยุดความสนุกและเริ่มเป็น PIA นักพัฒนาเหล่านั้นจะไปที่อื่น

BuildNotify.pyตัวอย่างเช่นผมส่งแพทช์ให้ ไม่ใช่เพราะฉันเห็นแก่ผู้อื่น แต่เป็นเพราะฉันใช้เครื่องมือนี้และฉันต้องการคุณสมบัติ มันง่ายดังนั้นที่นี่มีแพทช์ ถ้ามันซับซ้อนหรือยุ่งยากฉันจะไม่ใช้BuildNotify.pyและฉันจะหาอย่างอื่น หากทุกครั้งที่มีการอัพเดตเคอร์เนลออกมาตัวแก้ไขข้อความของฉันก็พังฉันจะใช้ระบบปฏิบัติการอื่น การมีส่วนร่วมของฉันต่อชุมชน (เล็ก ๆ ) จะไม่ดำเนินต่อไปหรือมีอยู่และอื่น ๆ

ดังนั้นการตัดสินใจในการออกแบบจึงเป็นการเรียกระบบที่เป็นนามธรรมดังนั้นเมื่อฉันทำfs.open()มันก็ใช้งานได้ นั่นหมายถึงการรักษาไว้fs.openนานหลังจากfs.open2()ได้รับความนิยม

ในอดีตนี้เป็นเป้าหมายของระบบ POSIX โดยทั่วไป "นี่คือชุดการโทรและค่าส่งคืนที่คาดไว้คุณจะคิดออกกลาง" อีกครั้งสำหรับเหตุผลการพกพา ทำไมไลนัสเลือกที่จะใช้วิธีการนั้นเป็นสิ่งที่อยู่ภายในสมองของเขาและคุณจะต้องขอให้เขารู้ว่าทำไม หากเป็นฉันเองฉันจะเลือกที่เป็นนามธรรมมากกว่าการรวมระบบที่ซับซ้อน


1
API ไปยัง userspace, 'syscall' API นั้นได้รับการกำหนดไว้อย่างดี (โดยเฉพาะส่วนย่อย POSIX) และมีความเสถียรเนื่องจากการลบส่วนใดส่วนหนึ่งของมันจะทำให้ซอฟต์แวร์เสียหายซึ่งคนอาจติดตั้งไว้ สิ่งที่ไม่มีคือAPI ไดรเวอร์ที่เสถียร
pjc50

4
@FaheemMitha เป็นวิธีอื่น ๆ นักพัฒนาเคอร์เนลมีอิสระในการทำลาย API ของไดรเวอร์เมื่อใดก็ตามที่พวกเขาต้องการตราบใดที่พวกเขาแก้ไขไดรเวอร์ในเคอร์เนลทั้งหมดก่อนที่จะปล่อยรุ่นต่อไป มันกำลังทำลาย API ของผู้ใช้หรือแม้กระทั่งทำสิ่งที่ไม่ใช่ของ API ที่สามารถทำลายผู้ใช้ในพื้นที่ซึ่งก่อให้เกิดปฏิกิริยามหากาพย์จากไลนัส
ทำเครื่องหมาย

4
ตัวอย่างเช่นหากมีคนตัดสินใจที่จะเปลี่ยนมันโดยส่งคืนรหัสข้อผิดพลาดที่แตกต่างจาก ioctl () ในบางสถานการณ์: lkml.org/lkml/2012/12/23/75 (มีการสบถและการโจมตีส่วนบุคคลของผู้พัฒนาที่รับผิดชอบ) โปรแกรมแก้ไขดังกล่าวถูกปฏิเสธเพราะจะทำให้ PulseAudio เสียหายและด้วยเหตุนี้เสียงทั้งหมดในระบบ GNOME
pjc50

1
@FaheemMitha โดยทั่วไป def เพิ่ม (a, b); คืน a + b; จบ --- def เพิ่ม (a, b); c = a + b; ส่งคืน c; จบ --- def เพิ่ม (a, b); c = a + b +10; ผลตอบแทน c - 10; end - เป็นการนำ "เพิ่ม" มาใช้ทั้งหมด สิ่งที่ทำให้เขาอารมณ์เสียคือเมื่อคนเพิ่ม def (a, b); return (a + b) * -1; end ในสาระสำคัญการเปลี่ยนวิธีการ "สิ่งภายใน" เพื่อการทำงานของเคอร์เนลก็โอเค การเปลี่ยนสิ่งที่ส่งคืนไปยังการกำหนด API และ "การโทรสาธารณะ" ไม่ใช่ การเรียก API มีสองประเภท "ส่วนตัว" และ "สาธารณะ" เขารู้สึกว่าการเรียก API สาธารณะไม่ควรเปลี่ยนแปลงโดยไม่มีเหตุผลที่ดี
coteyr

3
ตัวอย่างที่ไม่ใช่โค้ด คุณไปที่ร้านคุณซื้อแก๊สอ็อกเทน 87 อัน คุณในฐานะผู้บริโภคไม่ได้ "ใส่ใจ" ว่าก๊าซมาจากไหนหรือถูกแปรรูปอย่างไร คุณแค่แคร์รับแก๊ส หากก๊าซผ่านกระบวนการกลั่นที่แตกต่างกันคุณไม่สนใจ แน่นอนว่ากระบวนการกลั่นสามารถเปลี่ยนแปลงได้ มีแหล่งน้ำมันต่างกัน แต่สิ่งที่คุณสนใจคือการได้รับก๊าซออกเทน 87 ดังนั้นตำแหน่งของเขาคือเปลี่ยนแหล่งกำเนิดเปลี่ยนโรงกลั่นเปลี่ยนสิ่งที่เคยมีมาตราบใดที่สิ่งที่ปั๊มออกมาคือ 87 อ็อกเทนแก๊ส ทุกสิ่งที่ "เบื้องหลัง" ไม่สำคัญ ตราบใดที่มีแก๊สออกเทน 87
coteyr

8

มันเป็นการตัดสินใจและการออกแบบ ไลนัสต้องการที่จะสามารถรับประกันกับผู้พัฒนาพื้นที่ผู้ใช้ว่ายกเว้นในสถานการณ์ที่หายากมากและพิเศษ (เช่นเกี่ยวกับความปลอดภัย) การเปลี่ยนแปลงในเคอร์เนลจะไม่ทำลายแอปพลิเคชันของพวกเขา

ข้อดีคือผู้ใช้งานของพื้นที่ผู้ใช้จะไม่พบรหัสของพวกเขากระทันหันในเมล็ดใหม่เนื่องจากเหตุผลตามอำเภอใจและแน่นอน

ข้อเสียคือเคอร์เนลต้องเก็บโค้ดเก่าและ syscalls เก่า ๆ ไว้ตลอดไป (หรืออย่างน้อยก็นานกว่าวันที่ใช้งานไปตามวันที่)


ขอบคุณสำหรับการตอบกลับ. คุณรู้หรือไม่ว่าประวัติศาสตร์ของการตัดสินใจครั้งนี้มีวิวัฒนาการอย่างไร? ฉันตระหนักถึงโครงการที่มีมุมมองที่แตกต่างออกไป ตัวอย่างเช่นโครงการ Mercurial ไม่มี API ที่แน่นอนและสามารถและทำลายรหัสที่ต้องใช้
Faheem Mitha

ไม่ขอโทษฉันจำไม่ได้ว่ามันเป็นอย่างไร คุณสามารถส่งอีเมลถึง Linus หรือ LKML และถามเขา
cas

2
Mercurial ไม่ใช่ระบบปฏิบัติการ จุดทั้งหมดของระบบปฏิบัติการคือการเปิดใช้งานการทำงานของซอฟต์แวร์อื่นที่อยู่ด้านบนของมันและทำให้ซอฟต์แวร์อื่น ๆ นั้นไม่เป็นที่นิยมอย่างมาก โดยการเปรียบเทียบ Windows ยังรักษาความเข้ากันได้ย้อนหลังเป็นเวลานานมาก รหัส Windows 16 บิตเพิ่งล้าสมัยไปเมื่อเร็ว ๆ นี้
pjc50

@ pjc50 มันเป็นความจริงที่ Mercurial ไม่ใช่ระบบปฏิบัติการ แต่ไม่ว่าจะมีซอฟต์แวร์อื่น ๆ แม้ว่าจะมีเพียงสคริปต์เท่านั้นก็ตาม และอาจถูกทำลายได้ด้วยการเปลี่ยนแปลง
Faheem Mitha
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.