왜 사용자 공간을 깨뜨리지 않는 Linux 커널 정책이 있습니까?


38

나는 Linux Kernel Mailing 목록에서 에티켓과 관련 하여이 문제에 대해 생각하기 시작했습니다. 세계에서 가장 잘 알려져 있고 틀림없이 가장 성공적이고 중요한 자유 소프트웨어 프로젝트 인 Linux 커널은 많은 압박을받습니다. 그리고 프로젝트 창립자이자 리더 인 Linus Torvalds는 여기서 소개 할 필요가 없습니다.

Linus는 때때로 LKML에서 화염으로 논란을 불러 일으킨다. 이러한 불꽃은 종종 자신의 입장에 따라 사용자 공간을 깨뜨리는 것과 관련이 있습니다. 내 질문에 나를 가져옵니다.

왜 사용자 공간을 깨뜨리는 것이 그렇게 나쁜지에 대한 역사적인 관점을 가질 수 있습니까? 내가 알기로, 사용자 공간을 깨 뜨리려면 응용 프로그램 수준에서 수정이 필요하지만 커널 코드를 개선하면 이것이 나쁜 것입니까?

내가 이해하는 것처럼 Linus의 명시된 정책은 사용자 공간을 깨뜨리지 않으면 코드 품질을 포함하여 다른 모든 것보다 우선한다는 것입니다. 이것이 중요한 이유는 무엇이며 그러한 정책의 장단점은 무엇입니까?

(Linus가 때때로이 주제에 대해 LKML의 최고 중위들과 의견을 달리하고 있기 때문에, 그러한 정책에 대해서는 분명히 일관된 정책이 적용되고있다.


1
소개에서 Linus의 철자가 틀 렸습니다.
Ismael Miguel

확실하지는 않았지만 투표를 잊고 투표를했습니다.
Ismael Miguel

답변:


38

그 이유는 역사적인 것이 아니라 실제적인 것입니다. Linux 커널 위에서 실행되는 많은 프로그램이 많이 있습니다. 커널 인터페이스가 해당 프로그램을 중단하면 모든 사람이 해당 프로그램을 업그레이드해야합니다.

이제 대부분의 프로그램은 실제로 커널 인터페이스 ( 시스템 호출 )에 직접 의존하지 않고 C 표준 라이브러리 ( 시스템 호출 주위의 C 래퍼) 인터페이스에만 의존한다는 것이 사실 입니다. 그러나 어떤 표준 라이브러리입니까? Glibc? uClibC? Dietlibc? 바이오닉? 머슬? 기타

그러나 OS 별 서비스를 구현하고 표준 라이브러리에 의해 노출되지 않은 커널 인터페이스에 의존하는 많은 프로그램도 있습니다. (리눅스는 이들의 많은 통해 제공되는 /proc/sys.)

그리고 정적으로 컴파일 된 바이너리가 있습니다. 커널 업그레이드로 이들 중 하나가 중단되면 유일한 해결책은 다시 컴파일하는 것입니다. 소스가있는 경우 : Linux는 독점 소프트웨어도 지원합니다.

소스를 사용할 수있는 경우에도 모두 모으는 것은 어려울 수 있습니다. 특히 하드웨어 버그를 수정하기 위해 커널을 업그레이드 할 때 특히 그렇습니다. 사람들은 종종 하드웨어 지원이 필요하기 때문에 나머지 시스템과 독립적으로 커널을 업그레이드합니다. Linus Torvalds말에서 :

사용자 프로그램을 깨는 것은 용납되지 않습니다. 우리는 사람들이 오래된 바이너리를 수년 동안 사용한다는 것을 알고 있으며, 새로운 릴리스를 만든다고해서 그냥 버릴 수 있다는 것을 의미하지는 않습니다. 당신은 우리를 믿을 수 있습니다.

그는 이것을 강력한 규칙으로 만드는 한 가지 이유는 새로운 커널을 작동시키기 위해 다른 프로그램을 업그레이드해야 할뿐만 아니라 다른 프로그램과 다른 프로그램을 업그레이드 해야하는 종속성 지옥을 피하기 위해서 라고 설명 합니다. 모든 것이 특정 버전의 모든 것에 의존하기 때문입니다.

그건 어느 정도 잘 정의 된 편도 종속성이 괜찮습니다. 슬프지만 때로는 불가피합니다. (…) 좋지 않은 것은 양방향 의존성을 갖는 것입니다. 사용자 공간 HAL 코드가 새로운 커널에 의존한다면 괜찮습니다. 비록 사용자가 그것이 "금주의 커널"이 아니라 "지난 몇 달 동안의 커널"이되기를 바랍니다.

그러나 TWO-WAY 종속성이 있으면 문제가 생깁니다. 즉, 잠금 단계로 업그레이드해야하며 수락 할 수 없습니다. 사용자에게는 끔찍하지만, 더 중요한 것은 개발자에게 끔찍합니다. "버그가 발생했다"고 말할 수없고 이등분으로 좁히려 고 시도하는 것과 같은 일을하기 때문입니다.

사용자 공간에서 이러한 상호 종속성은 일반적으로 다른 라이브러리 버전을 유지하여 해결됩니다. 그러나 하나의 커널 만 실행할 수 있으므로 사람들이 원하는 모든 것을 지원해야합니다.

공식적 으로

[시스템 호출이 안정적으로 선언 됨]의 이전 버전과의 호환성은 2 년 이상 보장됩니다.

실제로는

syscall과 같은 대부분의 인터페이스는 절대 변경되지 않으며 항상 사용 가능합니다.

더 자주 변경되는 것은 하드웨어 관련 프로그램에서만 사용되는 인터페이스입니다 /sys. ( /proc반대로, /sys비 하드웨어 관련 서비스 용으로 도입 된 이후 로 호환되지 않는 방식으로 중단되지는 않습니다.)

요약하자면,

사용자 공간을 깨 뜨리려면 응용 프로그램 수준에서 수정이 필요합니다.

사람들이 나머지 시스템과 독립적으로 업그레이드하기를 원하는 커널이 하나 밖에 없기 때문에 나쁘지만 복잡한 상호 의존성을 가진 많은 응용 프로그램이 있습니다. 수백만 개의 다른 설정에서 수천 개의 응용 프로그램을 최신 상태로 유지하기 위해 커널을 안정적으로 유지하는 것이 더 쉽습니다.


1
답변 감사합니다. 안정적인 것으로 선언 된 인터페이스는 POSIX 시스템 호출의 상위 집합입니까? 역사에 대한 나의 질문은이 관습이 어떻게 진화했는지입니다. 아마도 리눅스 커널의 원래 버전은 최소한 초기에는 사용자 공간 손상에 대해 걱정하지 않았습니다.
Faheem Mitha

3
@FaheemMitha 그렇습니다 . 1991 년 이래로 해냈습니다 . Linus의 접근 방식이 발전했다고 생각하지 않습니다. 항상 "일반 응용 프로그램의 인터페이스는 변경되지 않으며, 커널 변경과 매우 밀접한 관련이있는 소프트웨어의 인터페이스는 거의 변경되지 않습니다."
Gilles 'SO- 악마 그만해

24

상호 의존적 시스템에는 기본적으로 두 가지 선택이 있습니다. 추상화 및 통합. (의도적으로 기술 용어를 사용하지 않습니다). Abstraction을 사용하면 API에 대한 코드가 변경 될 수 있지만 결과는 항상 동일하다는 API를 호출 할 수 있습니다. 예를 들어 전화를 걸 때 fs.open()네트워크 드라이브, SSD 또는 하드 드라이브인지는 신경 쓰지 않고 항상 열려있는 파일 설명자를 얻을 수 있습니다. "통합"의 목표는 방법이 바뀌더라도 일을하는 "최상의"방법을 제공하는 것입니다. 예를 들어, 파일을 여는 것은 디스크의 파일과 네트워크 공유의 경우 다를 수 있습니다. 두 가지 방법 모두 최신 Linux 데스크탑에서 광범위하게 사용됩니다.

개발자 관점에서는 "모든 버전에서 작동"또는 "특정 버전에서 작동"이라는 문제입니다. 이에 대한 좋은 예는 OpenGL입니다. 대부분의 게임은 특정 버전의 OpenGL에서 작동하도록 설정되어 있습니다. 소스에서 컴파일하는 것은 중요하지 않습니다. 게임이 OpenGL 1.1을 사용하도록 작성되었고 3.x에서 실행하려고한다면 좋은 시간이 없을 것입니다. 스펙트럼의 다른 쪽 끝에서 일부 호출은 무엇이든 작동 할 것으로 예상됩니다. 예를 들어, 나는 fs.open()어떤 커널 버전을 사용하고 싶지는 않지만 전화 하고 싶습니다. 파일 설명자가 필요합니다.

각 방법에는 이점이 있습니다. 통합은 이전 버전과의 호환성을 유지하면서 "최신"기능을 제공합니다. 추상화는 "최신"호출보다 안정성을 제공합니다. 중요하지는 않지만 중요하지는 않습니다.

공동의 관점에서 볼 때, 정말 좋은 이유가 없다면 복잡한 시스템에서는 추상화가 항상 더 좋습니다. 예를 들어 fs.open()커널 버전에 따라 다르게 작동 하는지 상상해보십시오 . 그런 다음 간단한 파일 시스템 상호 작용 라이브러리는 수백 가지의 "열린 파일"방법 (또는 아마도 블록)을 유지해야합니다. 새로운 커널 버전이 나오면 "업그레이드"할 수 없으며 사용한 모든 소프트웨어를 테스트해야합니다. 커널 6.2.2 (가짜)는 텍스트 편집기를 손상시킬 수 있습니다.

일부 실제 사례에서 OSX는 사용자 공간을 깨뜨리는 것에 신경 쓰지 않는 경향이 있습니다. 그들은 더 자주 "추상"보다 "통합"을 목표로합니다. 그리고 모든 주요 OS 업데이트에서 문제가 발생합니다. 한 가지 방법이 다른 방법보다 낫다는 것은 아닙니다. 선택과 디자인 결정입니다.

가장 중요한 것은 Linux 에코 시스템은 사람들이나 그룹이 자유 시간에 프로젝트를 수행하거나 도구가 유용하기 때문에 멋진 오픈 소스 프로젝트로 채워져 있다는 것입니다. 이를 염두에두고 재미를 멈추고 PIA가되기 시작하면 개발자들은 다른 곳으로 갈 것입니다.

예를 들어,에 패치를 제출했습니다 BuildNotify.py. 이타 적이기 때문이 아니라 도구를 사용하기 때문에 기능을 원했습니다. 쉬웠으므로 여기 패치가 있습니다. 복잡하거나 성 BuildNotify.py가시면 사용하지 않고 다른 것을 찾을 것입니다. 커널 업데이트가 텍스트 편집기에서 나올 때마다 다른 OS를 사용합니다. 커뮤니티에 대한 나의 기여는 (작지만 작음) 계속되거나 존재하지 않을 것입니다.

따라서 디자인 결정은 시스템 호출을 추상화하여 결정했을 때 fs.open()작동합니다. 그것은 인기 fs.openfs.open2()얻은 후에 오래 유지하는 것을 의미합니다 .

역사적으로 이것은 POSIX 시스템의 목표입니다. "여기에는 일련의 호출과 예상 반환 값이 있습니다. 중간을 찾으십시오." 이식성의 이유로 다시 한 번. Linus가이 방법론을 사용하기로 선택한 이유는 그의 뇌 내부에 있으며, 그 이유를 정확히 알아야합니다. 그러나 그것이 저라면 복잡한 시스템의 통합보다 추상화를 선택합니다.


1
사용자 공간에 대한 API 인 'syscall'API는 잘 정의되어 있으며 (특히 POSIX 하위 집합), 일부를 제거하면 사람들이 설치했을 수있는 소프트웨어가 손상 될 수 있기 때문에 안정적입니다. 그것이없는 것은 안정적인 드라이버 API입니다.
pjc50

4
@FaheemMitha, 그것은 다른 길입니다. 커널 개발자는 다음 릴리스 이전에 모든 커널 내부 드라이버를 수정하는 한 원하는 경우 언제든지 드라이버 API를 중단 할 수 있습니다. 사용자 공간 API를 깨뜨 리거나 사용자 공간을 깨뜨릴 수있는 비 API 작업을 수행하여 Linus의 서사시 반응을 만듭니다.
Mark

4
예를 들어, 어떤 상황에서 누군가가 ioctl ()에서 다른 오류 코드를 리턴하여 변경하기로 결정한 경우 : lkml.org/lkml/2012/12/23/75 (책임자에 대한 맹세 및 개인 공격 포함). 이 패치는 PulseAudio와 그놈 시스템의 모든 오디오를 손상시켜 거부되었습니다.
pjc50

1
@FaheemMitha, 기본적으로 def add (a, b); a + b를 반환; 끝 --- def add (a, b); c = a + b; 리턴 c; 끝 --- def add (a, b); c = a + b +10; 반환 c-10; end-add의 "동일한"구현입니다. 그를 화나게하는 것은 사람들이 def add (a, b); return (a + b) * -1; 본질적으로 커널에 "내부"사물이 작동하는 방식을 바꾸는 것은 괜찮습니다. 정의 된 "공용"API 호출로 리턴되는 내용은 변경되지 않습니다. "private"과 "public"의 두 가지 API 호출이 있습니다. 그는 합당한 이유없이 공개 API 호출이 변경되지 않아야한다고 생각합니다.
coteyr

3
비 코드 예제; 당신은 가게에 가서 87 옥탄 가스를 구입합니다. 소비자는 가스의 출처 나 처리 방법을 "관리"하지 않습니다. 가스를받는 것만 신경 쓰세요. 가스가 다른 정제 공정을 거쳤다면 걱정하지 않아도됩니다. 정제 과정이 변경 될 수 있는지 확인하십시오. 기름의 공급원도 다양합니다. 그러나 당신이 걱정하는 것은 87 옥탄 가스를 얻는 것입니다. 펌프에서 나오는 것이 87 옥탄 가스 인 한, 그의 위치는 소스 변경, 정련소 변경, 무엇이든 변경됩니다. 모든 "장면"내용은 중요하지 않습니다. 87 옥탄 가스가있는 한.
coteyr

8

디자인 결정과 선택입니다. Linus는 매우 드물고 예외적 인 (예 : 보안 관련) 상황을 제외하고 커널 변경으로 인해 응용 프로그램이 중단되지 않는 사용자 공간 개발자에게 보장 할 수 있기를 원합니다.

장점은 사용자 공간 개발자가 임의의 변덕스러운 이유로 새로운 커널에서 갑자기 코드를 깨뜨리지 않는다는 것입니다.

단점은 커널이 오래된 코드와 오래된 시스템 콜 등을 영원히 (또는 적어도 사용 날짜가 지난 것 이상) 유지해야한다는 것입니다.


답장을 보내 주셔서 감사합니다. 이 결정이 어떻게 발전했는지의 역사를 알고 있습니까? 다소 다른 관점을 취하는 프로젝트를 알고 있습니다. 예를 들어 Mercurial 프로젝트에는 고정 된 API가 없으며이를 사용하는 코드를 중단 할 수 있습니다.
Faheem Mitha

아뇨, 죄송합니다. 어떻게되었는지 기억이 나지 않습니다. Linus 또는 LKML로 이메일을 보내어 물어볼 수 있습니다.
cas

2
Mercurial은 OS가 아닙니다. OS의 전체 요점은 다른 소프트웨어를 실행하고 다른 소프트웨어를 파괴하는 것이 매우 인기가 없다는 것입니다. 이에 비해 Windows는 이전 버전과의 호환성도 오랫동안 유지해 왔습니다. 16 비트 Windows 코드는 최근에 더 이상 사용되지 않습니다.
pjc50

@ pjc50 그것은 거기, 의욕에 관계없이 OS가 아니라 것은 사실 이다 다른 소프트웨어는 스크립트 것은,에 의존하는 경우에도. 그리고 변경으로 인해 잠재적으로 손상 될 수 있습니다.
Faheem Mitha
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.